java中x (x-1)_如何理解x&(-x), x&(x-1) ?

算法题里面,涉及到按位运算,有2个经典位运算:

x&(-x) : 保留二进制下最后出现1的位置的数字,其余位置置0;

x&(x-1) : 清除二进制下最后出现1的位置的数字,其余位置保持不变;

x可以将二进制数写作(A) 1 (B)的形式,其中A表示一系列01串,1表示从右向左出现的第一个数字1,B表示空串(x是奇数)或者全0串(x是偶数)。那么,

x是奇数时,x = (A) 1

x是偶数时,x = (A) 1 (0..0)

对于x&(-x)

推演

1)先求-x,

-x代表x的相反数,在计算机中存储的是补码,也就是说,-x实际存储的是x反码 + 1

x是奇数时,-x = (~A) 0 + 1 = (~A) 1

x是偶数时,-x = (~A) 0 (1..1) + 1 = (~A) 1 (0..0)

2)再求x&(-x),

x是奇数时,x&(-x) = (0..0) 1

x是偶数时,x&(-x) = (0..0) 1 (0..0)

其中,1右边的0位数保持不变。也就是说x&(-x) 会保留二进制最右边出现的1位置对于数字,其余位置置0。

应用

求非负整数x能被2的n次幂整除的n最大值。

考虑:

如果x为奇数,∵x无法被2整除,只能被1整除 ∴n=0

如果x为偶数,∵整除一个2的n次幂数,相当于右移n位

∴要求n的最大值,等价于求x最多能右移位数保持位1个数不变的移动数量 <=> 求x最右边连续0的个数

如8 = 1000b,右移3位1个数不变,右移4位1的个数减少,而8最大能被2^3整除。

24 = 1 1000b,右移3位1个数不变,右移4位1个数减少,而24最大能被2^3整除。

故只需要保留最右边的1即可,因为只需要计算最右边连续0的个数。

#include

int maxPowerOfTwo(int d) {

d = d&(-d);

int num = 0;

while(d) {

num ++;

d = d >> 1;

}

return num-1;

}

int main(void) {

int n = maxPowerOfTwo(24);

printf("%d\n", n);

return 0;

}

对于x&(x-1)

推演

1)先求x-1,

x是奇数时,x-1 = (A) 0

x是偶数时,x-1 = (A) 0 (1..1)

2)再求x&(x-1)

x是奇数时,x&(x-1) = (A) 0

x是偶数时,x&(x-1) = (A) 0 (0..0)

其中,原来1(现在的0)右边的位数保持不变。

应用

示例1:求32位整型数d对应二进制数包含的1的个数。

#include

// 求二进制数d包含1的位数

int countBitOne(int d) {

int num = 0;

while(d)

{

num++;

d = d & (d-1);

}

return num;

}

int main(void) {

int d = 0b101000;

int nums = countBitOne(d);

printf("%d\n", nums);

return 0;

}

示例2:判断一个数是否为2的n次方。

思路:

2的n次方是形如1,2,4,8,16,32,...这样的数

1 -- 1b

2 -- 10b

4 -- 100b

8 -- 1000b

16 - 10000b

32 - 100000b

...

这样数的特点是二进制数据只包含1个位1,如果能将唯一的1清除,则必为0。考虑使用x&(x-1)将二进制数最后一位1清除。

#include

#include

bool isTwoPower(int d) {

if (d&(d-1) == 0) {

return true;

}

return false;

}

推论

x - x&(-x) = x&(x-1)

左边式子表示在二进制数x基础上,清除最右边为1的数,与右边式子含义一样。

REF

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值