开启掘金成长之旅!这是我参与「掘金日新计划 · 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的某次方,主要利用了二进制的特性以及右移运算。
如果你有更好的办法,欢迎在评论区留言交流。