如何生成二进制字符串的所有可能子集?

时间:2010-03-31 22:44:09

标签: c++ algorithm

我有一个问题,我不知道如何解决它。

我有一个二进制字符串,我想生成所有可能的二进制子串。

示例:

input : 10111
output: 10000, 10100,00111,00001,10110 ...

我怎样才能做到这一点,快速而聪明?

5 个答案:

答案 0 :(得分:6)

Magic - 虽然假设了bitmask:

subset( int x ) 
    list = ()
    for ( int i = x; i >= 0; i = ( ( i - 1 ) & x ) )
          list.append( i )
    return list

你可以使用相同的逻辑,虽然它涉及更多,使用二进制字符串。

答案 1 :(得分:2)

没关系 - 该死的我忘了你用字符串而不是int / long / what。你仍然可以使用相同的逻辑...只计算二进制,但只使用包含1的位置。

大声思考。

我们取字符串1001

我想,你想要的是四个数字1001,1000,0001和0000,是吗?

如果是这样,你正在做的是计算“那些”的位置。

一种方法是存储原始号码

orig = n;

然后开始迭代那个和每个较低的数字

while(n--)

但是每次迭代都会忽略试图将1放在0位置的那些:

    if(n & !orig)
        continue;

如果你期望它是稀疏的 - 就像很少有1的零那样,你可以使用移位机制。所以我们说你的号码是1000 1001

注意有三个1,对吗?所以只计算从000到111

但是对于每次迭代,再次将这些位分散开来:

n& 0000 0001 | n<< 2& 0000 1000 | n<< 5& 1000 0000

或另一种思考方式:

n& 001 | (n& 010)* 1000 | (n& 100)* 1000 000

这可能比其他解决方案慢,这取决于出现了多少1,因为它涉及内部循环,原始数字中的每个1都有1次迭代。

很抱歉在二进制和十进制之间转换 - 如果您愿意,我可以用十六进制全部完成:)

现在我无法想出一个直接映射位而不移位的模式 - 这样效果最好。

答案 2 :(得分:1)

使用递归

printsubsets(const string &in, const string &out)
{
  if(in.empty())
  {
    cout<<out<<"\n";
    return;
  }

  if(in[0]=='1')
    printsubsets(in.substr(1), out+"1");
  printsubsets(in.substr(1), out+"0");
}

答案 3 :(得分:1)

这样做:

vector<string> submasks(string in)
{
    vector<string> out;

    out.push_back(string(in.size(), '0'));

    for (int i = 0; i < in.size(); ++i)
    {
        if (in[i] == '0') continue;

        int n = out.size();
        for (int j = 0; j < n; ++j)
        {
            string s = out[j];
            s[i] = '1';
            out.push_back(s);
        }
    }

    return out;
}

算法执行此操作:

  1. 从仅包含空位字符串'00000 ...'
  2. 的向量开始
  3. 对于输入字符串中的每个1:使用该集合在输出向量中创建每个字符串的副本。
  4. 我认为这非常优秀。

答案 4 :(得分:0)

  1. 如果您只想要低于二进制字符串数值的值,请继续从二进制字符串中取一个,直到达到0.
  2. 如果您想要所有可以用该二进制数字表示的值,请从该数字位数可以表示的最高数字中减去1,直至达到0.
  3. 这类问题出现在那些代码katcha网站上