Description
給定一個 32 位元無號整數,將其二進位反轉後回傳結果。
Example:
Input: n = 00000010100101000001111010011100 Output: 964176192 (00111001011110000010100101000000)
Intuition#
核心思路:逐位從 n 取出最低位,左移放入結果的對應位置。
- 想像把一個 32 位元的數字「鏡像翻轉」
- 每次取 n 的最低位,放到結果的高位;迭代 32 次完成反轉
- 也可以用分治法,先交換相鄰的 1-bit 區塊,再交換 2-bit 區塊,依此類推
Approaches#
1: 逐位反轉#
- 概念: 迭代 32 次,每次把 n 的最低位取出,左移放入結果
- 時間複雜度:
O(32)=O(1) - 空間複雜度:
O(1)
class Solution {
fun reverseBits(n: Int): Int {
var result = 0
var num = n
for (i in 0 until 32) {
result = result shl 1
result = result or (num and 1)
num = num ushr 1
}
return result
}
}⭐2: 分治法(Divide and Conquer)#
- 概念: 用遮罩分層交換:先交換相鄰 1 位、再交換相鄰 2 位、4 位、8 位、最後 16 位
- 時間複雜度:
O(1)- 固定 5 步操作 - 空間複雜度:
O(1)
class Solution {
fun reverseBits(n: Int): Int {
var num = n
num = ((num and 0x55555555.toInt()) shl 1) or ((num ushr 1) and 0x55555555.toInt())
num = ((num and 0x33333333) shl 2) or ((num ushr 2) and 0x33333333)
num = ((num and 0x0f0f0f0f) shl 4) or ((num ushr 4) and 0x0f0f0f0f)
num = ((num and 0x00ff00ff) shl 8) or ((num ushr 8) and 0x00ff00ff)
num = (num shl 16) or (num ushr 16)
return num
}
}Kotlin 中沒有無號整數運算子,需要用
ushr(unsigned shift right)來避免符號擴展問題。同時0x55555555超出 Int 正數範圍,需要.toInt()轉換。
補充:Integer.reverse 內建函數
Java/Kotlin 的 Integer.reverse 內部實作就是分治法:
class Solution {
fun reverseBits(n: Int): Int {
return Integer.reverse(n)
}
}🔑 Takeaways#
- Pattern: 逐位處理和分治法是位元操作的兩大基本策略
- 關鍵技巧: 分治法用特定遮罩(0x55555555, 0x33333333 等)交換位元區塊,這組遮罩在很多位元問題中反覆出現