算法:返回离非负整数num最近的2的某次方

题目描述

给定一个非负整数num,如何不用循环语句,返回>=num,并且离num最近的,2的某次方

题目解析

思路:

将这个数字最高位 1 之后的所有位都填上 1,最后加一,就是大于N的最小的 2 的 N 次方。右移一位,就是小于N的最大的 2 的N次方。

如何将最高位的1之后全部变为1

假设有一个数n,它的二进制位表示如下:
0100 , 0000 0100 ,0000 01000000

那么 n = n ∣ ( n > > 1 ) n = n | (n >> 1) n=n(n>>1),得到如下:
0110 , 0000 0110 ,0000 01100000

那么 n = n ∣ ( n > > 2 ) n = n | (n >> 2) n=n(n>>2),得到如下:
0111 , 1000 0111 ,1000 01111000

那么 n = n ∣ ( n > > 4 ) n = n | (n >> 4) n=n(n>>4),得到如下:
0111 , 1111 0111,1111 01111111

因此,下面代码的意思是:

    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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值