在数字的二进制表示中检查所有设置位的最佳方法之后是仅未设置的位

时间:2017-12-24 14:59:50

标签: java data-structures bit-manipulation time-complexity

你能不能让我知道有没有最好的办法找到这个数字的二进制表示设置位后面跟着未设置的位只有像 - 4 - 100 6 - 110 8 - 1000 12 - 1100

private static boolean setBitFollowedByUnsetBits(int num) {
    String str = Integer.toBinaryString(num);
    int len = str.length();
    int countof1 = str.indexOf('0');
    int lastIndOf0 = str.lastIndexOf('0');
    int countof0 = lastIndOf0 -countof1;
    int lastIndOf1 = str.lastIndexOf('1');

    if((!(lastIndOf1 > countof1) && (lastIndOf1 < lastIndOf0))) {
        return ((num >> countof0+1)==((2 << countof1-1)-1));
    }   
    return false;
}

这就是我所写的逻辑,但我正在寻找更有效的更好的解决方案。

4 个答案:

答案 0 :(得分:1)

阐述@ Alberto的提示:

您正在寻找像0000 0000 0111 1111 1100 0000 0000 0000(我假设32位整数)的位模式:

  • 一些领先的零位(没有也没关系)
  • 一位(至少一位)
  • 的块
  • 一个零比特块(至少一个)

特殊情况可以是所有零比特(N == 0),或以一比特结尾的数字(没有尾随零比特)。让我们首先看一下通用案例:

具有N = xxxx1000这样的二进制数,则N-1为xxxx0111,将所有尾随零位替换为1位,将最右边的1位替换为0位,并保持较高位不变。 / p>

ORing N与N-1类似int K = N | (N-1);用一位替换尾随零位:

N   = xxxx1000
N-1 = xxxx0111
      --------
K   = xxxx1111

我们希望xxxx部分类似于0001.现在,让我们反转K:

~K  = yyyy0000

其中yyyy是xxxx的按位反转,应该看起来像1110.所以,再一次,我们可以检查尾随的零位并用int L = (~K) | ((~K)-1);设置它们。如果原始数字中只有一个1比特的块,结果现在应该都是一比特。

现在特殊情况:

  • 如果N中根本没有一位,结果也会给出所有的一位。由于缺少一位块,结果应该是假的,需要特殊处理。

  • 只包含一个1位块的数字也会产生所有1。但是由于缺少尾随零位,它应该返回false,需要特殊处理,只需要查看最后一位为零。

所以代码如下:

private static boolean setBitFollowedByUnsetBits(int num) {
    if (num == 0) return false;
    if ((num & 1) == 1) return false;
    int invK = ~ (num | (num-1));
    int indicator = invK | (invK-1);
    return indicator == 0xffffffff;
}

答案 1 :(得分:0)

你可以适应Brian Kernigan的算法 https://www.geeksforgeeks.org/count-set-bits-in-an-integer/

a)初始化计数:= 0
b)如果整数n不为零

  1. 按位&amp;使用(n-1)并将值赋值回n

    {n:= n&amp;(n-1)}

  2. 增量计数为1

  3. 转到步骤b
  4. c)其他回报计数

    如上面的链接中所解释的,从数字中减去1将所有位(从右到左)切换到最右边的设置位(包括最右边的设置位)。因此,如果我们将数字减1并按比例减去&amp;与自身(n&amp;(n-1)),我们取消设置最右边的设置位。如果我们做n&amp; (n-1)在一个循环中计算循环执行的次数,我们得到设定的位数。

答案 2 :(得分:0)

我认为更有效的方法是进行按位检查而不是string -> integer转换并使用字符串进行操作。

private static boolean check(int value) {
    int h = SIZE - numberOfLeadingZeros(value);
    boolean one = false;
    boolean zero = false;
    for (int i = h - 1; i >= 0; i--) {
        int mask = 1 << i;
        if ((value & mask) == mask) {
            if (!zero) {
                one = true;
            } else {
                return false;
            }
        } else {
            if (one) {
                zero = true;
            } else {
                return false;
            }
        }
    }
    return one && zero;
}

答案 3 :(得分:0)

我就是这样做的。

private static boolean setBitFollowedByUnsetBits(int num) {
    int withoutTrailingZeros = num >>> Integer.numberOfTrailingZeros(num);
    return num != 0 && (withoutTrailingZeros & withoutTrailingZeros + 1) == 0;
}

这是有效的,因为您的问题实际上是移出尾随零,Java具有快速内置函数,然后测试剩余数字是否已设置所有位(直到最高位)。您可以按位进行此操作,对于任何数字n,如果n & n + 1设置了所有位,则0仅为n(见下文)。我假设您不希望0返回true,因为它没有设置位,但如果不是这样,您可以删除num != 0 &&

   111 // 7
& 1000 // 8
= 0000 // 0, so 7 has all bits set

   101 // 5
&  110 // 6
=  100 // 4, so 5 does not have all bits set

修改:如果号码必须有一些尾随零,您还可以检查withoutTrailingZeros != num是否为true