题目描述
给定一个非负整数num,如何不用循环语句,返回>=num,并且离num最近的,2的某次方
题目解析
思路:
将这个数字最高位 1 之后的所有位都填上 1,最后加一,就是大于N的最小的 2 的 N 次方。右移一位,就是小于N的最大的 2 的N次方。
如何将最高位的1之后全部变为1
假设有一个数n,它的二进制位表示如下:
0100
,
0000
0100 ,0000
0100,0000
那么
n
=
n
∣
(
n
>
>
1
)
n = n | (n >> 1)
n=n∣(n>>1),得到如下:
0110
,
0000
0110 ,0000
0110,0000
那么
n
=
n
∣
(
n
>
>
2
)
n = n | (n >> 2)
n=n∣(n>>2),得到如下:
0111
,
1000
0111 ,1000
0111,1000
那么
n
=
n
∣
(
n
>
>
4
)
n = n | (n >> 4)
n=n∣(n>>4),得到如下:
0111
,
1111
0111,1111
0111,1111
因此,下面代码的意思是:
temp |= temp >> 1;
temp |= temp >> 2;
temp |= temp >> 4;
temp |= temp >> 8;
temp |= temp >> 16;
对于数temp,它的二进制表示从最高位的1开始全部变1
001
?
?
?
?
?
?
?
?
?
−
−
−
>
0011111111
001????????? ---> 0011111111
001?????????−−−>0011111111
为什么只需要算到16,因为整型只有32位。
如果是long类型,那么多一个 temp |= temp >> 32;即可
举个例子:
如果 n = 13 ,那么它的二进制是:
0000
,
1101
0000,1101
0000,1101
然后x = n - 1,x的二进制为:
0000
,
1100
0000,1100
0000,1100
然后对x进行或操作,将最高位开始全部变1,得到y= 0000 , 1111 0000,1111 0000,1111
然后对y+1,得到ans = 0001 , 0000 0001,0000 0001,0000
举个例子:
如果 n = 29,那么它的二进制是:
0001
,
1101
0001,1101
0001,1101
然后x = n - 1,x的二进制为:
0001
,
1100
0001,1100
0001,1100
然后对x进行或操作,将最高位开始全部变1,得到y= 0001 , 1111 0001,1111 0001,1111
然后对y+1,得到ans = 0010 , 0000 0010,0000 0010,0000,
得到64
举个例子:
如果 n = 16,那么它的二进制是:
0001
,
0000
0001,0000
0001,0000
然后x = n - 1,x的二进制为:
0000
,
1111
0000,1111
0000,1111(这也是为啥要减1的原因)
然后对x进行或操作,将最高位开始全部变1,得到y= 0000 , 1111 0000,1111 0000,1111
然后对y+1,得到ans = 0001 , 0000 0001,0000 0001,0000,
得到16
int tableSize(int n){
n--; //让代码更叫精简,不用对N是不是2的某次方做定制
n |= (unsigned int)n >> 1;
n |= (unsigned int)n >> 2;
n |= (unsigned int)n >> 4;
n |= (unsigned int)n >> 8;
n |= (unsigned int)n >> 16; //从最高位的1开始全部填满1
return (n < 0) ? -1 : n + 1; //里负数最近的2的某次方是1
}
int main() {
printf("%d\r\n", tableSize(7));
printf("%d\r\n", tableSize(8));
printf("%d\r\n", tableSize(-8));
printf("%d\r\n", tableSize(13));
return 0;
}