开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第35天,点击查看活动详情
前言
本文主要介绍如何寻找距离int
型整数num
最近的2的某次方。
要求给出一个整数num
,在不使用循环语句的情况下,返回大于等于num
并且距离num
最近的2
的某次方。
例如,num=3
,距离最近并且大于num
的数为2;num=5
,距离最近并且大于num
的数为2。
思路分析
num为负数
如果num
为负数的话,比较简单,因为2
的几次方,肯定是个正数,无论负数num
为多少,大于等于num
的2的某次方肯定为2。
num为正数
如果num
为正数的话,我们从二进制上来看看如何处理。
2
的n次方的二进制信息是如何表示的呢?他的二进制表现形式为,在第n
位置上为1
,其他位置全部为0
。
假如num
的二进制信息为0010101001
,那距离这个数的2
的n次方是多少呢?只需要把num
的二进制最高位的1
往前移动一位,也就是0100000000
。
那么如何得到这个数呢?我们把0100000000
这个数减去个1
来看下,得出的结果为0011111111
,这个数和num
的二进制0010101001
最高位的1
是一样的,只是右边全部为1
。
那么接下来只需要把num
的二进制信息最高位1
右边变成1
就可以了。
转换为1
由于不能使用循环判断,我们从位运算方面出发。
这里用到的是或运算,或运算的规则为1|1=1
、1|0=1
、0|0=0
。
我们不知道num
的数值是多少,他的最高位的1有可能在0~31位的任何位置,所以要做好最坏的打算。
假设num
的二进制信息为001100001
,根据这个我们来看下计算过程。
-
001100001
右移1
位为0001100000
,并将两个数进行或运算,结果为0011100001
。 -
0011100001
右移2
位为0000111000
,并将两个数进行或运算,结果为0011111001
。 -
0011111001
右移4
位为0000001111
,并将两个数进行或运算,结果为0011111111
。
从上面过程可以看到,经过3
次右移操作,就可以把二进制001100001
最高位1
右侧的数全部变为1
。
但是,由于我们并不知道num
具体是多少,所以做好最坏的打算,最坏的打算就是把32
位全部变为1
。
所以,需要右移的位数应该为:1
位、2
位、4
位、8
位、16
位。
刚好为2的某次方
如果这个num
本身就为2的某次方,还能用上述的操作过程吗?也是可以的,只不过最后不需要进行加1
。
所以,为了保证计算逻辑的统一,我们先把num
这个数一上来就进行减1
操作,这样的话,如果这个num
本身就为2的某次方,则运算逻辑和前面分析的一样,如果不是的话,也没什么影响。
代码实现
经过前面的逻辑分析,我们来看下代码实现,其实代码非常简单,我们一起来看下。
public class Code21_FindNear2PowerNum {
public static int find(int num) {
if (num <= 0) {
return 1;
}
num --;
num |= num >>> 1;
num |= num >>> 2;
num |= num >>> 4;
num |= num >>> 8;
num |= num >>> 16;
return num + 1;
}
public static void main(String[] args) {
int res = find(-15);
System.out.println(res);
res = find(5);
System.out.println(res);
res = find(11);
System.out.println(res);
res = find(20);
System.out.println(res);
}
}
运行代码,输出结果为:
1
8
16
32
总结
本文主要介绍如何寻找距离int
型整数num
最近的2的某次方,主要利用了二进制的特性以及右移运算。
如果你有更好的办法,欢迎在评论区留言交流。