| title | 2^31. 2 的幂 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| description | LeetCode 2^31. 2 的幂题解,Power of Two,包含解题思路、复杂度分析以及完整的 JavaScript 代码实现。 | ||||||||
| keywords |
|
🟢 Easy 🔖 位运算 递归 数学 🔗 力扣 LeetCode
Given an integer n, return true if it is a power of two. Otherwise,
return false.
An integer n is a power of two, if there exists an integer x such that n == 2x.
Example 1:
Input: n = 1
Output: true
Explanation: 20 = 1
Example 2:
Input: n = 16
Output: true
Explanation: 24 = 16
Example 3:
Input: n = 3
Output: false
Constraints:
-2^31 <= n <= 2^31 - 1
Follow up: Could you solve it without loops/recursion?
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。
示例 1:
输入: n = 1
输出: true
解释: 20 = 1
示例 2:
输入: n = 16
输出: true
解释: 24 = 16
示例 3:
输入: n = 3
输出: false
提示:
-2^31 <= n <= 2^31 - 1
进阶: 你能够不使用循环/递归解决此问题吗?
- 不断将
n除以 2,直到n为 1。如果途中有无法整除的情况,则说明n不是 2 的幂。 - 如果
n <= 0,直接返回false,因为负数和 0 不可能是 2 的幂。
var isPowerOfTwo = function (n) {
if (n <= 0) return false;
while (n > 1) {
if (n % 2 !== 0) return false;
n = n / 2;
}
return true;
};- 时间复杂度:
O(log n),n每次被除以 2,最多进行log n次操作。 - 空间复杂度:
O(1),不需要额外空间。
- 2 的幂次方的特点是它的二进制表示中只有一位是
1,例如:1(2^0) 是00012(2^1) 是00104(2^2) 是01008(2^3) 是1000
- 判断是否是 2 的幂次方,只需检查
n是否大于 0 且满足n & (n - 1) == 0。n & (n - 1)会将n的最低位的 1 变为 0,而其他位保持不变。如果结果为 0,则n是 2 的幂次方。
var isPowerOfTwo = function (n) {
return n > 0 && (n & (n - 1)) === 0;
};- 时间复杂度:
O(1),只需一次按位操作。 - 空间复杂度:
O(1)。
- 如果
n是 2 的幂次方,则log2(n)是整数。 - 用
Math.log2(n)计算log2(n),检查是否为整数。
var isPowerOfTwo = function (n) {
if (n <= 0) return false;
return Math.log2(n) % 1 === 0;
};- 时间复杂度:
O(1),Math.log2()是常数时间操作。 - 空间复杂度:
O(1)。
- 使用最大范围内的 2 的幂次方数(如
2^30 = 1073741824,因为2^31已超过 32 位整数范围)。 - 如果
n是 2 的幂次方,则它一定能整除2^30。
var isPowerOfTwo = function (n) {
return n > 0 && 1073741824 % n === 0;
};- 时间复杂度:
O(1),只有一次取模操作。 - 空间复杂度:
O(1)。
- 如果
n是 2 的幂次方,则n应该等于 1 或者能被 2 整除后递归调用自身继续判断。
var isPowerOfTwo = function (n) {
if (n <= 0) return false;
if (n === 1) return true;
return n % 2 === 0 && isPowerOfTwo(n / 2);
};- 时间复杂度:
O(log n),n每次递归减小一半。 - 空间复杂度:
O(log n),递归调用栈的深度。
- 预先存储所有 2 的幂次方(例如
2^0, 2^1, ..., 2^30)。 - 用一个集合存储这些值,判断时直接查找。
const powersOfTwo = new Set();
for (let i = 0; i <= 30; i++) {
powersOfTwo.add(1 << i); // 2^i
}
var isPowerOfTwo = function (n) {
return powersOfTwo.has(n);
};- 时间复杂度:
O(1),查找集合中的元素是常数时间操作。 - 空间复杂度:
O(1),集合的大小固定为 31 个元素。
| 解法 | 时间复杂度 | 空间复杂度 | 优缺点 |
|---|---|---|---|
| 逐步除以 2 | O(log n) |
O(1) |
简单易懂,但不够高效 |
| 按位与操作 | O(1) |
O(1) |
最优解,高效且简洁 |
| 对数判断 | O(1) |
O(1) |
需依赖浮点运算,可能有精度问题 |
| 模运算 | O(1) |
O(1) |
易于实现,但需硬编码最大范围 |
| 递归法 | O(log n) |
O(log n) |
直观,但递归调用消耗较大 |
| 预计算法 | O(1) |
O(1) |
适合范围固定的场景 |
推荐使用 按位与操作 解法,兼具高效性和代码简洁性。
| 题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
|---|---|---|---|---|---|
| 191 | 位1的个数 | [✓] | 位运算 分治 |
🟢 | 🀄️ 🔗 |
| 326 | 3 的幂 | [✓] | 递归 数学 |
🟢 | 🀄️ 🔗 |
| 342 | 4的幂 | [✓] | 位运算 递归 数学 |
🟢 | 🀄️ 🔗 |