1. 描述
给定一个数n,找出不超过n的最大的2的幂指数x,例如
- 当 n = 1时,x = 1;
- 当 n = 2时,x = 2;
- 当 n = 3时,x = 2;
- 当 n = 9时,x = 8;
2. 用途
在一些数字计算、分裂、复制类的问题中,可能会用到;
3. 方法
3.1 常规方法
常规的方法就是累乘,让1不断的去乘于2,此时应注意越界;
- 代码实现
public int largerPowerOfTwo(int n) { int res = 1; // stop是防止int越界 int stop = Integer.MAX_VALUE / 2; while (n >= res && res < stop) { res *= 2; } return res > stop ? res : (res / 2); }
- 时间复杂度:O(logN)
- 空间复杂度:O(1)
3.2 位运算方法
通过或和无符号右移运算,
- 通过无符号右移,把1的位置向右移动;
- 通过或
- 代码实现
public static int largerPowerOfTwo(int n) { n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; // n + 1 可能会越界,变成负的最小值,无符号右移,最高位补0,不影响结果 return (n + 1) >>> 1; }
- 时间复杂度:O(1)
- 空间复杂度:O(1)
4. 说明
4.1 位运算方法
- 通过5次无符号位移,总共位移32位,如果是long类型的,在加一次位移
n |= n >>> 32
;(n + 1) >>> 1
中,n+1
可能会越界,变成10000000 0000000 00000000 00000000
,但是经过无符号右移1次,最高位补0,就变成01000000 0000000 00000000 00000000
,不影响最终的结果;(n + 1) >>> 1
改为(n >>> 1) + 1
不会越界,但是当输入为0时,结果不是0而是1;
5. 总结
- 累乘就很快了、位移操作开发中基本用不到,jdk中Integer包装中常用,开阔一下思路;
- 总结记录