231 Power of Two
这题三种解法,重点掌握bit manipulation的
- loop
- recursion
- bit manipulation
利用的性质是,如果一个数n能被表示成\(2^x\), where \(x\in \mathbb{N^*}\), 那么除了x = 0, 其它x都满足n & (n-1) == 0. 这个性质可以用来判断一个数是否是2的幂次方。
Approach 1 loop
判断对于一个integer n, 是否存在另一个interger x 使得 \(2^x = n\),那么你的solution就只能是,
$$ 2^x \quad x\in \mathbb{N^{*}} $$ where \(\mathbb{N}^{*}\) is 正整数.
Tip
注意,在计算机和集合论中,\(\mathbb{N}\) 定义为包括0的正整数. 但在数论中,\(\mathbb{N}\) 定义为不包括0的正整数. 所以在这里做了区分。Conventionally, \(\mathbb{N^0}\) is used to denote the set of non-negative integers, \(\mathbb{N}^{*}\) for positive integers. 如果你想严谨一些的话.
既然结果肯定是, {1, 2, 4, 8, 16...}, 我的思路是设计一个从0不断乘以2的循环,直到找到一个数等于n,或者超过n.
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
counter = 0
bar = 2**counter
while bar <= n:
if bar == n:
return True
counter += 1
bar = 2**counter
return False
Follow-up: w/o loop/recursion
能否不用loop或者recursion来求呢? 对于2的幂次方,有一个快速判断的trick, 也就是& operator的性质, 先看如下表
| \(2^x\) | in binary | \(2^x - 1\) | in binary |
|---|---|---|---|
| \(2^0 = 1\) | 0001 | \(2^0 -1 = 0\) | 0000 |
| \(2^1 = 2\) | 0010 | \(2^1 -1 = 1\) | 0001 |
| \(2^2 = 4\) | 0100 | \(2^2 -1 = 3\) | 0011 |
| \(2^3 = 8\) | 1000 | \(2^3 -1 = 7\) | 0111 |
| \(2^4 = 16\) | 10000 | \(2^4 -1 = 15\) | 01111 |
| \(2^5 = 32\) | 100000 | \(2^5 -1 = 31\) | 011111 |
我们随便取俩做个计算, 比如2=0010 and 1=0001
0010
& 0001
------
0000
对于一个power of two的数,它的二进制表示中只有一个1,所有其他位都是0. 所以它减去1的话,就是lower bits都是1. 所以它们的&操作结果就是0.
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
"""
1: 0:
01 00
2: 1:
10 01
4: 3:
100 011
8: 7:
1000 0111
16 15:
10000 01111
so for n = 2^x, we always have the properties that n & (n-1) == 0
"""
if n <= 0: return 0
return n & (n-1) == 0