2的幂

题目介绍

利空i231题:https://leetcode-cn.com/problems/power-of-two/
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
在这里插入图片描述

分析

本题是一个数学问题。在计算机系统中,2的整次幂往往有非常重要的意义,往往是众多数据类型能够表示的数值边界,是真正的“整数”。2的整次幂,有很多重要的性质:

  • 能被2连续整除
  • 写成2进制的形式,就是一个1后面跟着n个0(n≥0)

我们可以利用这些特性,构造出不同的解法。

方法一:除2判断余数

最简单的想法,就是借鉴十进制转换二进制的方法,不断地除以2,判断当前余数是否为0,只要中间出现了1,那就不是2的整次幂。这里需要注意的是,即使是2的整次幂,最后也应该有一次余数为1。

那如何判断当前余数1是“中间产生”还是“最终产生”呢?只需要看当前的被除数是否为1就可以了:如果是最后一次除法,被除数应该就是1。

代码如下:

public class PowerOfTwo {
    // 方法一:除2判断余数
    public boolean isPowerOfTwo(int n){
        if (n <= 0) return false; 
        // 不停地除以2 
        while (n % 2 == 0)
            n /= 2;
        return n == 1;
    }
}

复杂度分析

  • 时间复杂度:O(logn)。循环的次数,就是二进制展开的位数,也就是以2为底n的对数。
  • 空间复杂度:O(1)。

方法二:位运算(与自身减1做位与)

对于这样一个数学问题,O(logn)的时间复杂度显然不能让我们满意。我们可以利用之前分析的2的幂第二个特性来进行优化,也就是说:写成2进制形式后,就是一个1后面跟着k个0(k≥0)。

这种形式有一个非常明显的性质,就是减1之后,就会变成k个1。所以我们可以发现,对于2的幂,这个数自身和它减1之后的数,进行位与运算,得到的结果应该是0;或者进行异或运算,得到的结果应该是k+1个1。

当然很明显,位与运算的结果更好判断。写成逻辑表达式就是:

n & (n - 1) == 0

代码如下:

// 方法二:位运算(与自身减1做位与)
public boolean isPowerOfTwo(int n){
    if (n <= 0) return false;
    return (n & n - 1) == 0;
}

复杂度分析

  • 时间复杂度:O(1)。只需要做一次位运算。
  • 空间复杂度:O(1)。

方法三:位运算(与相反数做位与)

由于2的幂的二进制表达中,只有一个1,所以另外一个思路是,我们可以试图获取二进制数中最右端的1。我们现在要保留最后一位1,其它位全部变0,如果等于自身,那就是2的幂。

要想其它位都变为0,容易想到,如果取反码,然后跟自身做位与,自然就全是0了。如果再加1,就可以保留最后一位1了。

我们知道,在计算机底层,负数的补码表示,就是反码加1。所以我们要做的,就是让n和-n做位与运算。得到的,就只有最右面一位1,其它位都为0。

在这里插入图片描述
在这里插入图片描述
如果当前数n为2的幂,那么最右面的一位1,其实就是最高位的1;保留这一位,其实跟原数是完全相等的。
写成表达式就是:

n & (-n) == n

代码如下:

// 方法三:位运算(与相反数做位与)
public boolean isPowerOfTwo(int n){
    if (n <= 0) return false;
    return (n & -n) == n;
}

复杂度分析

  • 时间复杂度:O(1)。
  • 空间复杂度:O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值