「你知道怎麼找出陣列裡唯一出現一次的那個數字嗎?」
面試官問這道題時,我第一直覺是用 HashMap。結果他說:「能不能不用額外空間?」 我卡住了。答案只需要一個 XOR 操作:把所有數字都 XOR 一遍, 相同的就抵消成 0,唯一剩下的就是答案。 這就是 Bit Manipulation 的魔法——用二進位的性質,把複雜問題變成一行。
位元操作基礎
在深入題目之前,把最常用的位元操作整理成一張速查表。 這六個操作是 Bit Manipulation 題目的全部武器庫。
| 操作 | 符號 | 範例 | 常見用途 |
|---|---|---|---|
| AND | a & b | 5 & 3 = 1 (101 & 011) | 取特定位、判斷奇偶 n & 1 |
| OR | a | b | 5 | 3 = 7 (101 | 011) | 設定特定位 |
| XOR | a ^ b | 5 ^ 3 = 6 (101 ^ 011) | 找唯一值、swap、missing number |
| NOT | ~a | ~5 = -6 (反轉所有位) | Python 少用,注意補數 |
| 左移 | a << k | 1 << 3 = 8 (× 2^k) | 快速計算 2 的冪次 |
| 右移 | a >> k | 8 >> 2 = 2 (÷ 2^k) | 取高位 / DP counting bits |
XOR 三大性質(背起來!)
a ^ a = 0
相同值抵消
→ 找重複 / missing
a ^ 0 = a
與 0 XOR 不變
→ 初始值設 0
XOR 可交換結合
a^b^c = c^a^b
→ 順序不影響結果
Number of 1 Bits
給一個整數,計算其二進位表示中有幾個 1(Hamming Weight)
Input: n = 11 (二進位 0b1011)
三個位置有 1 → 回傳 3
方法一:逐位右移(直覺解)
每次用 n & 1 取最低位, 再 n >>= 1 右移,直到 n 為 0。
方法二:Brian Kernighan 演算法(面試最愛)
關鍵觀察:n & (n-1) 會移除 n 的最低位的 1。 所以執行幾次操作、n 就變 0,次數就是 1 的個數。
n = 12(1100)的過程
count = 2 ✓(12 = 1100 只有 2 個 1)
Counting Bits
給 n,回傳一個長度 n+1 的陣列,ans[i] = i 的二進位中 1 的個數
Input: n = 5
| i | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| 二進位 | 0 | 1 | 10 | 11 | 100 | 101 |
| ans[i] | 0 | 1 | 1 | 2 | 1 | 2 |
DP 解:右移 + 最低位
核心規律:把 i 右移一位(i >> 1)就是把最低位去掉, 所以 ans[i] = ans[i >> 1] + (i & 1)。
遞推驗證
為什麼這個 DP 成立?
任何整數 i 的二進位,去掉最低位(i >> 1)就是 i/2 的二進位。 它的 1 的個數只比 i 多或少最低位那一個。 所以 ans[i] = ans[i/2] + (i是奇數?1:0), 而且因為 i/2 一定比 i 小,前面的值已經計算好了,DP 成立。
Missing Number
陣列包含 0 到 n 中的 n 個不同數字,找出缺少的那一個
Input: nums = [3, 0, 1](n=3)
應該有 0,1,2,3 四個數,但只有三個 → 缺少的是 2
方法一:數學公式(簡單)
0~n 的總和 = n*(n+1)//2, 減去陣列實際的總和,差值就是缺少的數字。
方法二:XOR(面試加分)
把 「理想值 0,1,2,...,n」和「實際陣列值」全部 XOR 在一起。 出現兩次的數字互相抵消,只剩下缺少的那一個。
nums=[3,0,1] 的 XOR 過程
result = 0
i=0: result ^= 0 ^ nums[0] = 0 ^ 0 ^ 3 = 3
i=1: result ^= 1 ^ nums[1] = 3 ^ 1 ^ 0 = 2
i=2: result ^= 2 ^ nums[2] = 2 ^ 2 ^ 1 = 1
最後: result ^= n = 1 ^ 3 = 2 ✓
等效於:(0^1^2^3) ^ (3^0^1) = 2, 0,1,3 各出現兩次被抵消,只剩 2。
Single Number
陣列中每個數字都出現兩次,只有一個數字出現一次,找出它
Input: nums = [4, 1, 2, 1, 2]
XOR 一行解
利用 XOR 的交換結合律,把所有數字 XOR 在一起。 出現兩次的數字 a ^ a = 0, 只剩唯一出現一次的那個。
nums=[4,1,2,1,2] XOR 過程
4 ^ 1 ^ 2 ^ 1 ^ 2
= 4 ^ (1 ^ 1) ^ (2 ^ 2) ← 重新排列
= 4 ^ 0 ^ 0
= 4 ✓
面試追問:如果有一個出現三次呢?(#137 Single Number II)
需要對每個 bit 位取模 3:用兩個變數 ones, twos, 分別記錄出現 1 次和 2 次的 bits,出現 3 次的 bit 就被清掉。 這是進階題,掌握基本 XOR 後再挑戰。
Bit Manipulation 解題模板
取最低位的 1
lowest_bit = n & (-n) # 或: n & ~(n-1)
統計 1 的個數、找特定位
移除最低位的 1
n &= (n - 1) # 每次移除最低的 1
#191 Number of 1 Bits
取第 k 位
bit_k = (n >> k) & 1 # k 從 0 開始
DP Counting Bits
XOR 找唯一值
result = 0
for num in nums:
result ^= num#136 Single Number、#268 Missing
各題解法比較
| 題目 | 最優解法 | Time | Space | 關鍵技巧 |
|---|---|---|---|---|
| #191 Number of 1 Bits | Brian Kernighan | O(k) | O(1) | n &= (n-1) |
| #338 Counting Bits | DP + 右移 | O(n) | O(n) | ans[i] = ans[i>>1] + (i&1) |
| #268 Missing Number | 數學公式 | O(n) | O(1) | n*(n+1)/2 - sum |
| #136 Single Number | XOR All | O(n) | O(1) | a^a=0,成對抵消 |
本篇重點回顧
上一篇
EP.20 — Heap
Kth Largest、Top K Frequent、Find Median
下一篇
EP.22 — Math
Palindrome Number、快速冪、Happy Number、Count Primes