231. 2 的幂

一个数 \(n\)\(2\) 的幂,当且仅当 \(n\) 是正整数,并且 \(n\) 的二进制表示中仅包含 1 个 1。

因此我们可以考虑使用位运算,将 \(n\) 的二进制表示中最低位的那个 \(1\) 提取出来,再判断剩余的数值是否为 \(0\) 即可。下面介绍两种常见的与「二进制表示中最低位」相关的位运算技巧。

第一个技巧是

\[\texttt{n & (n - 1)} \]

其中 \(\texttt{&}\) 表示按位与运算。该位运算技巧可以直接将 \(n\) 二进制表示的最低位 \(1\) 移除,它的原理如下:

假设 \(n\) 的二进制表示为 \((a 10\cdots 0)_2\) ,其中 \(a\) 表示若干个高位,1 表示最低位的那个 1,\(0\cdots 0\) 表示后面的若干个 \(0\),那么 \(n-1\) 的二进制表示为:

\[(a 01\cdots1)_2 \]

我们将 \((a 10\cdots 0)_2\)\((a 01\cdots1)_2\) 进行按位与运算,高位 \(a\) 不变,在这之后的所有位都会变为 0,这样我们就将最低位的那个 1 移除了。

因此,如果 \(n\) 是正整数并且 \(\texttt{n & (n - 1) = 0}\),那么 \(n\) 就是 2 的幂。

第二个技巧是\(\texttt{n & (-n)}\) 其中 \(-n\)\(n\) 的相反数,是一个负数。该位运算技巧可以直接获取 \(n\) 二进制表示的最低位的 1。

由于负数是按照补码规则在计算机中存储的,\(-n\) 的二进制表示为 \(n\) 的二进制表示的每一位取反再加上 1,因此它的原理如下:

假设 \(n\) 的二进制表示为 \((a 10\cdots 0)_2\) ,其中 \(a\) 表示若干个高位,1 表示最低位的那个 1,\(0\cdots 0\) 表示后面的若干个 0,那么 \(-n\) 的二进制表示为:

\[(\bar{a} 01\cdots1)_2 + (1)_2 = (\bar{a} 10\cdots0)_2 \]

其中 \(\bar{a}\) 表示将 \(a\) 每一位取反。我们将 \((a 10\cdots 0)_2\)\((\bar{a} 10\cdots0)_2\) 进行按位与运算,高位全部变为 0,最低位的 1 以及之后的所有 0 不变,这样我们就获取了 \(n\) 二进制表示的最低位的 1。

因此,如果 \(n\) 是正整数并且 \(\texttt{n & (-n) = n}\),那么 \(n\) 就是 2 的幂。

注意点

在一些语言中,位运算的优先级较低,需要注意运算顺序。

class Solution {
public:
    bool isPowerOfTwo(int n) {
        return n > 0 && (n & (n - 1)) == 0;
    }
};
class Solution {
public:
    bool isPowerOfTwo(int n) {
        return n > 0 && (n & -n) == n;
    }
};
posted @ 2021-07-16 17:48  Dazzling!  阅读(42)  评论(0编辑  收藏  举报