题目是实现将一个int 型数转化,转化方式如下:
如 5 是 101 翻转后是 010 也就是2
如 8 是 1000 翻转后是 0111 也就是7
实现方法一:
int findComplement(int num) {unsigned mask=~0;
while(mask&num) mask<<=1;
return mask^~num;
}
假设num=5 ,~num就是0xfffa; 把多余的位去掉就是答案
mask=0 ~mask=0xffff;
while(mask&num) mask<<=1; 结果mask=0xfff8; 多余的位全是1
剩下只需要再做一次异或,去掉多余的位 mask^~num
实现方法2
int findComplement(int num)
{
mask=num;
mask|=mask>>1;
mask|=mask>>2;
mask|=mask>>4;
mask|=mask>>8;
mask|=mask>>16;
return mask^num;
}
假设num=1001,目的使mask为1111,这样mask^num 就能直接得到结果。
为什么这样就能得到1111呢
考虑最极端也就是1最少的情况,num=1000,(为什么不是0100,因为这样根据要求num=100)
每做一次运算,1的个数加倍,经过以上5步运算总能达到1111,要是0x8000运行5步刚好32个1.
最后做一次异或就能得到结果了。
实现方法3
int findComplement(int num)
{
return ~num & ((1 <<(int)log2(num))-1);
}
这里和方法2的思路是一样的,(int)log2(num)+1是二进制的位数。 假设
num=1001 (1 <<(int)log2(num))-1 快速求出掩码1111
实现方法4
int findComplement(int num)
{
for(long i=0;i<=num;i*=2) num^i;
return num;
}
这里逐位进行翻转,单步算一算应该能明白
这里注意为什么i 为long 而不是int
注意num最大 0-1<<31-1
若i为int,1<<32为0,重复循环