【问题标题】:Using distinct binary numbers to find subsets of a given set使用不同的二进制数来查找给定集合的子集
【发布时间】:2016-01-25 01:18:45
【问题描述】:

因此,挑战在于设计一种算法来打印给定集合n 的子集。

让我们设置 n 相等:

 n = {a,b,c}

stack overflow article 上,@Piva 提供了一个答案,它利用“从 0 到 2^n 的每个数字在其二进制表示中给出一个唯一的子集”这一事实来解决这个问题

我已经编写了@Piva 代码的 Javascript 版本,它运行良好。除了一行,我大部分都理解:

if(((i>>j) & 1) === 1)

我想我理解这行代码将 i 位右移,将 j 个零添加到 i 的二进制表示的开头。我也理解位明智的 & 正在将 i >>j 与 1 进行比较,并查看输出 i >> 的第一位是否打开。

但我不明白此操作如何识别唯一的二进制表示以及为什么 if(((i>>j) & 1) === 1) 为真意味着我们拥有给定 n 的唯一子集。

这是我的 Javascript 版本:

    function SubsetBuilder(set) {
        this.set = set;

    }

    SubsetBuilder.prototype.getSubsets = function () {
        var self = this;

        if (!self.set)
            return null;

        //recursive way, do next
        var getSubsetsAll = function (originalSet) {
            if (!originalSet) {
                return;
            }
        }

        var n = this.set.length;
        for(var i = 0; i < (1<<n); i++) {
            var subset = [];
            for (var j = 0; j < n; j++) {
                console.log('i:' + i + ", binary: " + i.toString(2));
                console.log('j:' + j + ", binary: " + j.toString(2));
                console.log('(i >> j):');
                console.log((i >> j));
                console.log('((i>>j) & 1):');
                console.log(((i >> j) & 1));
                if(((i>>j) & 1) === 1){ // bit j is on
                    subset.push(this.set[j]);
                }
                console.log('-------------------');
            }
            console.log(subset);
            console.log('-------------------');
        }
    }

    var set = ['a', 'b', 'c'];
    var obj = new SubsetBuilder(set);
    obj.getSubsets();

【问题讨论】:

  • 我已添加评论以回应您对答案的问题。我不认为这是一个全新的问题。

标签: javascript java c# algorithm big-o


【解决方案1】:

if(((i&gt;&gt;j) &amp; 1) === 1) 检查是否设置了 i 的第 j 位。

要了解其工作原理,请考虑二进制 101b 中的数字 5。 &gt;&gt; 只是一个移位(或等效地,除以 2n),&amp; 1 屏蔽了除最低有效位之外的所有位。

(101b >> 0) & 1 = (101b & 1) = 1
(101b >> 1) & 1 = ( 10b & 1) = 0
(101b >> 2) & 1 = (  1b & 1) = 1 

因此,一旦我们了解了位提取的工作原理,我们就需要了解为什么位提取等同于子集包含:

以下是我们如何将二进制数 0-7 映射到 {A,B,C} 的子集

0: 0 0 0   => {     }
1: 0 0 1   => {    A}
2: 0 1 0   => {  B  }
3: 0 1 1   => {  B A}
4: 1 0 0   => {C    }
5: 1 0 1   => {C   A}
6: 1 1 0   => {C B  }
7: 1 1 1   => {C B A}

显然我们已经列出了所有子集。

希望您现在可以明白为什么对 i 的第 j 位的测试等同于将第 j 个对象包含到第 i 个子集中。

【讨论】:

  • 好的,我到了那里,我担心我花了很长时间才能掌握这一点,尽管我已经编写了将近 20 年的代码,哈哈。所以我知道位掩码是一种“标记”集合 n 子集的方法。我现在看到了,感谢您的回答 if(((i>>j) & 1) === 1) 正在检查 i 的第 j 位是否为“ON”并且 i 是标记点的位掩码, 二进制 1 我们有一个唯一的子集。我想更清楚地说明几件事,尤其是运算符 >>。我了解 1> j 的问题
  • 我是否可以将 i >> j 解读为“在 i 的二进制符号的开头添加 j 个零”?
  • 在描述中更清楚地说明了每个操作员在做什么。
  • 很棒的答案,你这个人^n大声笑。最后一个问题,如果你能这么好,为什么我迭代 2^n-1 而不是 2^n,我知道我可以“通过克隆 S(n-1) 并将 n 添加到克隆来构建 S(n)集,但我仍然无法想象为什么它的 S(n-1) for i
  • 没关系,对于集合 {a,b,c} 我迭代了 8 次,我以为那里是 7 分钟
猜你喜欢
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多