目录

题目描述

231. 2 的幂

题意分析

输入是一个 32 位有符号整数 n,问是否存在非负整数 $x$ 使得 $n = 2^x$。要注意指数从 0 起算,所以 1 也算符合条件。

输入范围覆盖了负数和 0,这两类必须在一开始就判掉:$2^x$ 恒为正,任何非正数都不可能满足;同时最小值 -2^31 的补码位模式是「只有最高位是 1」,形式上和 2 的幂长得一模一样,如果不先做符号判断,纯位运算会把它误判成真。

题目没有给出任何数组或序列,只给一个数并要求判定一个乘法结构上的性质,说明可用的信息只有这个数本身的二进制形态。这提示答案应当是常数时间的,而不是从 1 开始不断翻倍去比对。

解法:清除最低位的 1

核心思路

正的 $2$ 的幂在二进制中恰好只有一个 1,例如 8 = 1000₂。对任意正整数 nn - 1 会把最低位的 1 变成 0,并把它右侧的 0 全变成 1,所以 n & (n - 1) 会清除 n 的最低位 1

因此,n 是 $2$ 的幂,当且仅当:

  1. n > 0
  2. 清除最低位 1 后结果为 0

正数判断不能省略。0 & (-1) == 0,而 0 不是 $2$ 的幂;32 位最小负数的补码也只有最高位为 1,同样会被纯位运算误判。

解题步骤

  1. n > 0 排除零和负数。
  2. 计算 n & (n - 1)
  3. 结果为 0,说明原数恰好只有一个二进制 1,返回真;否则返回假。

例如 16 = 10000₂15 = 01111₂,按位与为 0;而 12 = 1100₂,与 11 = 1011₂ 按位与后仍剩 1000₂,所以不是 $2$ 的幂。

代码实现

class Solution {
    public boolean isPowerOfTwo(int n) {
        return n > 0 && (n & (n - 1)) == 0;
    }
}
func isPowerOfTwo(n int) bool {
    return n > 0 && n&(n-1) == 0
}

复杂度分析

  • 时间复杂度:$O(1)$,只执行固定次数的整数运算。
  • 空间复杂度:$O(1)$。

关键点总结

  • $2$ 的幂的二进制特征是“正数且只有一个 1”。
  • n & (n - 1) 清除最低位 1n & -n 则提取最低位 1
  • 面试中不仅要写出一行代码,还要能解释 n - 1 的借位变化。
  • 判断 $4$ 的幂时还需额外限制这个 1 出现在偶数位,这是常见追问。

易错点总结

  • 漏掉 n > 00 和最小负数都会被误判。
  • 写成 n >= 0:仍然没有排除 0
  • 用浮点对数判断:边界附近可能受精度影响,且没有位运算直接。
  • 1 开始反复乘 2:能做,但需要处理溢出,复杂度也变为 $O(log n)$。

相似题目

题目 难度 考察点
342. 4的幂 简单 在单个 1 的基础上追加「1 必须落在偶数位」
326. 3 的幂 简单 底数非 2,二进制无捷径,改用整除或最大幂取模
191. 位1的个数 简单 把「抹最低位 1」变成循环,统计总次数
338. 比特位计数 简单 i & (i - 1) 建立递推,批量求一段区间
136. 只出现一次的数字 简单 考的是异或的自反性而非单个数的位模式