【问题标题】:How to iterate over subsets of a bitwise mask?如何迭代按位掩码的子集?
【发布时间】:2021-08-31 12:58:54
【问题描述】:

我有一个表示为整数的位掩码。掩码和整数仅限于 32 位整数。

我有兴趣检查给定掩码/整数的集合位的所有子集,但我不知道快速找到这些子集的好方法。

我一直在使用的解决方案是

for(int j = 1; j <= mask; ++j)
{
  if(j & mask != 0)
  {
    // j is a valid subset of mask
  }
}

但这需要从j = 1循环到mask,我认为应该有比这更快的解决方案。

还有比这更快的解决方案吗?

我的后续问题是,如果我想将子集限制为固定大小(即固定数量的设置位),是否也有一种简单的方法可以做到这一点?

【问题讨论】:

  • 这能回答你的问题吗? Interesting bitmask puzzle in C++
  • @harold 我认为第一个问题是这样,但我必须添加一个有点不同的后续问题,它将子集限制为固定大小。
  • 这比较棘手,但可以通过多种方式实现。您是否可以使用特定于平台的按位运算,例如pdep?这会让事情变得更容易(没有那个是可能的,但很麻烦)
  • mask = 0x110, j = 0x011, mask &amp; j = 0x010.
  • 这里是“Snoobing any Sets”的略微简化(但不是无循环)版本:stackoverflow.com/questions/19069488/…

标签: algorithm language-agnostic bit-manipulation


【解决方案1】:

对于长度为n 的位掩码,设置位的最大子集数可以是2^n - 1。因此,如果您想检查它们,我们必须遍历所有子集,因此最佳复杂度将是 O(mask)。代码无法进一步改进。

Ps:如果要统计子集的总数,可以用动态规划来解决,时间复杂度要好很多。

【讨论】:

  • 我不觉得你关于复杂性的论点很好。在最坏的情况中就是这样,但通常你可以做得更好,通过一个不平凡的因素。
  • 时间复杂度总是讲最坏的情况
  • 是的,这就是为什么在这里谈论时间复杂度是没有用的。
  • 你必须检查所有的子集,假设掩码是11111,现在每个5-bit 数字都是它的子集,除了'00000'。所以很明显你必须检查从0000111111的每个数字。
  • 如何写一个快捷方式来遍历n 数字而不实际遍历n 数字!
【解决方案2】:

给定xmask 中的位子集,按顺序排列的下一个子集是( (x|~mask) +1 ) &amp; mask。如果x==mask,这将归零。

对于具有固定位数的子集,我没有超级快速的方法。

【讨论】:

    【解决方案3】:

    在 C++ 中迭代 state 的所有 subset

    for (int subset=state; subset>0; subset=(subset-1)&state) {}
    

    这个技巧通常用于位掩码+dp问题。迭代所有 state 中的所有 subset 的总时间复杂度为 O(3^n),如果使用此问题中的代码,这比 O(4^n) 有很大改进。

    【讨论】:

      猜你喜欢
      • 2022-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-28
      • 1970-01-01
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      相关资源
      最近更新 更多