位运算的技巧

2019-09-03 10:29:36

  • x & (x - 1)

x & (x-1)相当于消除了 x 从右向左数遇到的第一个 1。

应用一、用 O(1) 时间检测整数 n 是否是 2 的幂次。

若 n 是 2 的幂次,则 n & (n - 1) == 0。

应用二、计算整数二进制中包含 1 的个数。

    public int countOnes(int num) {
        int res = 0;
        while (num != 0) {
            num = num & (num - 1);
            res++;
        }
        return res;
    }

应用三、将整数A转成整数B,需要修改多少bit。

A ^ B 后对其中 1 的个数计数即可。

 

  • 二进制子集快速计算

首先考虑特例,全1的情况,如111,其子集毫无疑问是001 - 111,可以不断的减1即可。

下面考虑一般情况,如1011,首先可以确定是其子集必然是比1011小的数字,所有如果我们依然去不断的减少1,并且进行判断无效位0,就可以得到其所有的子集,但是这种方法中间有很多的状态是无效的,如何快速得到子集呢。

先给一些结论:

1)subset <= num

2) subset1 > subset2 -> subset1 & num > subset2 & num

有了这两个结论就可以了,设s = num,s 是 num的子集,令s = (s - 1) & num,s 必然是第二大的子集,重复上述操作就能得到第三大的子集,一直到s == 0,就可以枚举掉所有的子集。

for (int s = mask; s > 0; s = (s - 1) & mask) {
    // s : mask 的子集   
}
    

 

  • x & -x

x & -x 在树状数组中有非常多的应用,可以通过x & -x来得到一个数的lowbit。这里的lowbit就是一个数末尾1所表示的数字,比如0100的lowbit就是4。

 

posted @ 2019-09-03 10:31  hyserendipity  阅读(211)  评论(0编辑  收藏  举报