C++ 计数位掩码,枚举0

C++ 计数位掩码,枚举0,c++,python,c,binary,C++,Python,C,Binary,我在一次采访中提出了以下问题,我相信我给出了一个有效的实现方案,但我想知道是否有更好的更快的实现方案,或者只是我错过了一个技巧 给定3个无符号30位整数,返回30位整数的数量,当与任何原始数字进行比较时,这些数字的相同位置位设置为1。也就是说,我们列举了所有的0 让我举个例子,但为了清楚起见,让我们使用4bit 鉴于: A = 1001 B = 0011 C = 0110 它应该返回8,因为集合中有8个4位整数。该组为: 0011 0110 0111 1001 1011 1101 1110 1

我在一次采访中提出了以下问题,我相信我给出了一个有效的实现方案,但我想知道是否有更好的更快的实现方案,或者只是我错过了一个技巧

给定3个无符号30位整数,返回30位整数的数量,当与任何原始数字进行比较时,这些数字的相同位置位设置为1。也就是说,我们列举了所有的0

让我举个例子,但为了清楚起见,让我们使用4bit

鉴于:

A = 1001
B = 0011
C = 0110
它应该返回8,因为集合中有8个4位整数。该组为:

0011
0110
0111
1001
1011
1101
1110
1111
现在我是如何计算出来的,就是取每个数字,枚举可能数集,然后计算所有不同的值。我是如何枚举集合的,从数字开始,加上一个数字,然后再加上它本身,直到到达掩码为止。数字本身在集合中,掩码(全部设置为1)也在集合中。例如,要枚举1001的集合:

1001 = the start
1011 = (1001 + 1) | 1001
1101 = (1011 + 1) | 1001
1111 = (1101 + 1) | 1001 (this is the last value as we have reached our mask)
对每个数字都这样做,然后数一数单数

在python代码中就是这样(但语言并不重要,只要您可以执行按位操作,因此为什么这个问题也被标记为c/c++):

现在,这是有效的,并给出了正确的答案,但我想知道我是否错过了一个技巧。因为问题是只问计数,而不是列举所有的值,也许有一个更快的方法。要么先组合数字,要么在不枚举的情况下获得计数。我有一种感觉。由于数字中包含大量的零,因此枚举数呈指数增长,这可能需要相当长的时间

如果您有一个B和C,那么位设置为1的一组数字的计数,其中A或B或C的相应位设置为1

有些人不理解这个问题(没有帮助,因为我没有首先正确地问)。让我们使用上面给定的A、B和C值:

A:

B:

C:

现在合并这些集合并计算不同的条目。这就是答案。有没有一种方法可以在不枚举值的情况下执行此操作

编辑:对不起,问题出错了。现已修复。

技巧1: 总答案是每个单独的30位数字的并集。这将转换为按位并集运算符或。 这意味着我们可以做
D=A | B | C
通过您的4位示例,我们得出
D=1111
现在我们只需要使用1个数字

技巧二: 一点数学知识告诉我们,对于每一个
1
,我们可能得到的一组数字会加倍。 这意味着你所需要做的就是将2提升到1的幂。用循环计数1,每次向下移动

bits = 0
D = 0b1111 #our number from trick 1
for i in range(4): #here 4 is the number of bits
    if D & 1:
        bits += 1
    D >>= 1 #drop off the smallest number
print 2 ** bits

在这种情况下,它将打印16个

编辑:更新的要求:给定3个无符号30位整数,返回30位整数的数量,当与任何原始数字进行比较时,这些数字的相同位置位设置为1。也就是说,我们列举了所有的0

好吧,这有点难。计算一个数很容易,因为在这种情况下,可能的整数数只取决于零位数,如下所示:

// Count bits not set
const size_t NUMBITS=30;
size_t c;
size_t v = num;
for (c=NUMBITS; v; v >>= 1) 
  c -= v & 1;

return c; 
天真地说,您可能会尝试将其扩展为三个整数,方法是对每个整数进行运算并对结果求和,但这是错误的,因为可能性必须是唯一的,例如给定的

A = 1001
B = 0011
C = 0110
你会数三次而不是一次,例如1111。您应该减去任意两个数字之间共享的组合数,但不能将任何组合减去两次。 <强>这只是Winston Ewert的答案的C++翻译!<强>

size_t zeroperms(size_t v)
{
    // Count number of 0 bits
    size_t c = 1;
    for (c=NUMBITS; v; v >>= 1)
        c -= v & 1;
    // Return number of permutations possible with those bits
    return 1 << c;
}

size_t enumerate(size_t a, size_t b, size_t c)
{
    size_t total = zeroperms(a) + zeroperms(b) + zeroperms(c);
    total -= zeroperms(a | b); // counted twice, remove one
    total -= zeroperms(b | c); // counted twice, remove one
    total -= zeroperms(a | c); // counted twice, remove one
    total += zeroperms(a | b | c); // counted three times, removed three times, add one
    return total;
}
size\u t zeroperms(size\u t v)
{
//计数0位的数目
尺寸c=1;
对于(c=NUMBITS;v;v>>=1)
c-=v&1;
//返回这些位可能的置换数
返回1
解释
设
S(n)
为编号
n
产生的集合

supers(n)
返回数字n的集合大小。
supers
不是一个好名字,但我很难想出一个更好的名字

诀窍是认识到
S(a)^S(b)=S(a | b)
。因此,使用super我可以计算出所有这些集合的大小


为了弄清楚剩下的,画一个集合的维恩图。

很抱歉我弄错了。首先,你在示例中使用了&而在代码中使用了than。其次,为什么1000在你的示例中不是一个解决方案?请你澄清一下,我很想理解:)我在这里遗漏了什么吗?当
0001
a
B上面,它给出了一个真实的答案。为什么不认为这是一个可能的解决方案?@JohnDibling不是真的。最好的解决方案可能不是最短的。
0101
不起作用吗?第一个
1
匹配C,第二个匹配a和B。更新后的问题更让人困惑。我现在完全不知道你在说什么重新询问。你的错误中是否包括错误?包括代码> 0代码/代码>技巧1稍微错误,C++中的代码> > <代码>是布尔的,或者不是按位的或.@ DayielRosiListBoer-OOP,尴尬的是如何打印8的4bit。example@dalore你错过了很多(8)在您的示例中,当A和BA=int('11111111111111111 0011111',2)B=int('1111111111111111111 00111111',2)C=int('1111111111111111111 01111111',2)打印解算('1111111111111 01101111',2)时,示例0001为真应该打印8,但是打印1073741816@dalore,我看到现在描述的问题与我写这篇文章时描述的问题不同。@dalore,如果我理解你的问题,现在应该是正确的。是的,这对我写的测试用例有效。接受这个答案,今天晚些时候,我将检查它以确保我理解它。看起来你是正确的计算比特数(我有一个理论,但无法使它起作用),然后删除你在其他人中已经计算过的比特数?@dalore,补充了一点解释这报告了1111111111111D的3个比特c的混乱
bits = 0
D = 0b1111 #our number from trick 1
for i in range(4): #here 4 is the number of bits
    if D & 1:
        bits += 1
    D >>= 1 #drop off the smallest number
print 2 ** bits
// Count bits not set
const size_t NUMBITS=30;
size_t c;
size_t v = num;
for (c=NUMBITS; v; v >>= 1) 
  c -= v & 1;

return c; 
A = 1001
B = 0011
C = 0110
size_t zeroperms(size_t v)
{
    // Count number of 0 bits
    size_t c = 1;
    for (c=NUMBITS; v; v >>= 1)
        c -= v & 1;
    // Return number of permutations possible with those bits
    return 1 << c;
}

size_t enumerate(size_t a, size_t b, size_t c)
{
    size_t total = zeroperms(a) + zeroperms(b) + zeroperms(c);
    total -= zeroperms(a | b); // counted twice, remove one
    total -= zeroperms(b | c); // counted twice, remove one
    total -= zeroperms(a | c); // counted twice, remove one
    total += zeroperms(a | b | c); // counted three times, removed three times, add one
    return total;
}
N = 4

def supers(number):
    zeros = sum(1 for bit in xrange(N) if (number >> bit) & 1 == 0)
    return 2**zeros


def solve(a,b,c):
    total = supers(a) + supers(b) + supers(c)
    total -= supers(a | b) # counted twice, remove one
    total -= supers(b | c) # counted twice, remove one
    total -= supers(a | c) # counted twice, remove one
    total += supers(a | b | c) # counted three times, removed three times, add one

    return total


print solve(0b1001,0b0011,0b0110)