检查在一系列位集中是否只设置了一位

时间:2013-04-09 08:52:00

标签: bit-manipulation

我正在努力找到实现这一目标的正确方法: 想象一下,我们有一组位集如下:

00100
00101
10000
00010
10001

我想测试一下,哪些位只在所有位集中设置一次。在示例中,结果将是:

00010

因为第4位是唯一一个在所有系列中只出现一次的位。

通过按位逻辑运算,哪种方法最好?

提前致谢。

3 个答案:

答案 0 :(得分:10)

正如您所看到的,您无法使用单个集合来存储中间结果,因为您需要区分每个位的3个状态:从不设置,设置一次并设置多次。

因此,您至少需要2个中间结果。例如,您可以跟踪至少设置一次的位和多次分别设置的位:

int atLeastOnce = 0;
int moreThanOnce = 0;
for (int current: sets) {
    moreThanOnce |= (atLeastOnce & current);
    atLeastOnce |= current;
}
int justOnce = atLeastOnce & ~moreThanOnce;

或者使用BitSet s(它看起来不那么优雅,因为BitSet不是不可变的):

BitSet atLeastOnce = new BitSet();
BitSet moreThanOnce = new BitSet();
for (BitSet current: sets) {
    BitSet moreThanOnceInCurrent = (BitSet) atLeastOnce.clone();
    moreThanOnceInCurrent.and(current);
    moreThanOnce.or(moreThanOnceInCurrent);
    atLeastOnce.or(current);
}
atLeastOnce.andNot(moreThanOnce);
BitSet justOnce = atLeastOnce;

答案 1 :(得分:4)

您可以使用一次两次的方法:

  • 为每个集合
    • 表示每个元素
      • 如果元素在once集合中
        • 将其添加到twice
      • 否则
        • 将其添加到once
  • 返回once - twice

这里的技巧是它可以并行执行:

  • 为每个集合C
    • twice:= twice或(once AND C
    • once:= onceC

实施可能如下:

BitSet once = new BitSet();
BitSet twice = new BitSet();
for(BitSet b : sets){
  BitSet mask = (BitSet) b.clone();
  mask.and(once);
  twice.or(mask);
  once.or(b);
}
once.andNot(twice);
return once;

答案 2 :(得分:1)

int length = 5;
int count[] = new int[length];
for (i = 0; i < bitset.length(); i++) {   
    int value = bitset[i];
    unsigned int count = 0;

    for (int j = 0; j < length; j++) {           // until all bits are zero
        if ((value & 1) == 1)     // check lower bit
            count[j]++;
        value >>= 1;              // shift bits, removing lower bit
    }
}

int number = 00000;
for (int k = 0; k < 5; k++) {
    if (count[k] == 1) 
         number = number | 1; 
    number >>= 1;
}

number is desired answer