🔢 Bit Manipulation

位元運算技巧與狀態壓縮。

11 題

📖 分類導讀

位元操作利用二進位的特性高效解題。常用操作包括 AND、OR、XOR、位移等。

Notes:

  • XOR 的特性:a ^ a = 0、a ^ 0 = a,常用於找唯一元素
  • 位移可以快速實現乘除 2 的冪次
  • n & (n - 1) 可以消除最低位的 1

技巧速查

目的寫法
取第 i 位(x shr i) and 1
設第 i 位為 1x or (1 shl i)
清除第 i 位x and (1 shl i).inv()
翻轉第 i 位x xor (1 shl i)
消去最低位的 1x and (x - 1)
取出最低位的 1x and (-x)
判斷奇偶x and 1
判斷 2 的冪x > 0 && (x and (x - 1)) == 0
計算 1 的個數Integer.bitCount(x)

NOTE

Kotlin 的位元運算用具名中綴函式 andorxorshlshrinv(),而非 C/Java 的 & | ^ << >> ~ushr 是無號右移。

位元向量(bitmap)

用一個整數(或整數陣列)的每個位元當一個布林旗標,能極省空間地表示「集合」或「狀態」:

  • 狀態壓縮:用一個 Int 的 32 位表示「哪些元素被選」,是狀態壓縮 DP(如旅行推銷員)與子集枚舉的基礎。
  • 去重 / 排序:值域有限且不重複時,用 bitmap 一個值一位,掃一遍標記,再從低到高讀出已標記位,即得 O(n) 排序兼去重——不需比較。
// 枚舉集合 {0..n-1} 的所有子集:用 mask 的每一位代表「該元素選不選」
fun subsets(nums: IntArray): List<List<Int>> {
    val n = nums.size
    val res = mutableListOf<List<Int>>()
    for (mask in 0 until (1 shl n)) {
        val subset = mutableListOf<Int>()
        for (i in 0 until n) {
            if ((mask shr i) and 1 == 1) subset.add(nums[i])
        }
        res.add(subset)
    }
    return res
}

TIP

XOR 還能做「不用暫存變數的交換」:a = a xor b; b = a xor b; a = a xor b。面試考點多於實用,但它體現了「用代數性質省空間」的思路。

跨倉庫導讀

#7Reverse IntegerMedium★★★★★⏱ O(log x)#29Divide Two IntegersMedium★★★★★⏱ O(log²n)#67Add BinaryEasy★★★★★⏱ O(max(m, n))#136Single NumberEasy★★★★⏱ O(n)#190Reverse BitsEasy★★★★★⏱ O(1)#191Number of 1 BitsEasy★★★★★⏱ O(k)#268Missing NumberEasy★★★★★⏱ O(n)#338Counting BitsEasy★★★★★⏱ O(n)#371Sum of Two IntegersMedium★★★★★⏱ O(32)#989Add to Array-Form of IntegerEasy★★★★★⏱ O(max(n, log k))#1470Shuffle the ArrayEasy★★★★★⏱ O(n)