思路
將一個數字的二進制左右翻轉,比如 11100→00111 。
假設原先的二進制數字為 abcdefgh
- 先1v1交換:ba dc fe hg
- 再2v2交換:dcba hgfe
- 再4v4交換:hgfedcba
這樣就把一個數字反轉了。
為什麼要用這樣看著多此一舉的操作?因為這些交換能用位運算表示。
在第一步時,往右交換的有四個數字 a c e g ,往左交換的有 b d f h 。
兩者都能用位運算獲得。
abcdefgh10101010a0c0e0g0&
,
abcdefgh010101010b0d0f0h&
此時將 a0c0e0g0 右移 1 位,將 0b0d0f0h 左移一位,
再將兩者or,就完成第一步的1v1交換了。
a0c0e0g0≫10b0d0f0h≪10a 0c 0e 0gb0 d0 f0 h0ba cd fe hgor
第二步,用類似的操作去完成後續的交換,移位的步數增加。
此時往右交換的數字有 ba fe ,往左交換的數字有 cd hg ,移位操作之後or。
bacdfehg11001100ba00fe00&
,
bacdfehg0011001100cd00hg&
,
ba00fe00≫200cd00hg≪200ba 00fecd00 hg00cdba hgfeor。
第三步,移位的步數增加。
此時往右交換的數字有 hgfe ,往左交換的數字有 cdba ,再透過移位操作or。
cdbahgfe11110000cdba0000&
,
cdbahgfe000011110000hgfe&
,
cdba0000≫4hgfe0000≪40000cdbahfge0000hgfecdbaor。
程式碼
位運算
class Solution {
public:
int reverseBits(int n) {
n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1); // 1010, 0101, 交換1位
n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2); // 1100, 0011, 交換2位
n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4); // 11110000, 00001111, 交換4位
n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8); // 交換 8 位
n = ((n & 0xffff0000) >> 16) | ((n & 0x0000ffff) << 16); // 交換 16 位
return n;
}
};
複雜度分析
- 時間複雜度:O(1)
- 空間複雜度:O(1)