算法 | 寻找距离整数num最近的2的某次方

1,364 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第35天,点击查看活动详情

前言

本文主要介绍如何寻找距离int型整数num最近的2的某次方。

要求给出一个整数num,在不使用循环语句的情况下,返回大于等于num并且距离num最近的2的某次方。

例如,num=3,距离最近并且大于num的数为22^2num=5,距离最近并且大于num的数为23^3

思路分析

num为负数

如果num为负数的话,比较简单,因为2的几次方,肯定是个正数,无论负数num为多少,大于等于num的2的某次方肯定为20^0

num为正数

如果num为正数的话,我们从二进制上来看看如何处理。

2的n次方的二进制信息是如何表示的呢?他的二进制表现形式为,在第n位置上为1,其他位置全部为0

image.png

假如num的二进制信息为0010101001,那距离这个数的2的n次方是多少呢?只需要把num的二进制最高位的1往前移动一位,也就是0100000000

那么如何得到这个数呢?我们把0100000000这个数减去个1来看下,得出的结果为0011111111,这个数和num的二进制0010101001最高位的1是一样的,只是右边全部为1

那么接下来只需要把num的二进制信息最高位1右边变成1就可以了。

转换为1

由于不能使用循环判断,我们从位运算方面出发。

这里用到的是或运算,或运算的规则为1|1=11|0=10|0=0

我们不知道num的数值是多少,他的最高位的1有可能在0~31位的任何位置,所以要做好最坏的打算。

假设num的二进制信息为001100001,根据这个我们来看下计算过程。

  1. 001100001右移1位为0001100000,并将两个数进行或运算,结果为0011100001

  2. 0011100001右移2位为0000111000,并将两个数进行或运算,结果为0011111001

  3. 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的某次方,主要利用了二进制的特性以及右移运算。

如果你有更好的办法,欢迎在评论区留言交流。