標籤:
題目:Reverse Bits
Reverse bits of a given 32 bits unsigned integer.
For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).
Follow up:
If this function is called many times, how would you optimize it?
PS:leetcode
一般的解決方案就是從左至右判斷每一位,把獲得的結果加在結果上,編碼如下,
class Solution {public: uint32_t reverseBits(uint32_t n) { uint32_t bit = 0; uint32_t result = 0; uint32_t tmp = n; while(bit<32) { if((tmp>>bit) & 1 == 1) result = result + (1<<(31-bit)); bit ++; } return result; }};
這種方式簡單易懂,但是效率不高,時間複雜度為O(n),n為資料類型的位元。
咱們換個角度想想,既然我們給定的數可以通過移動獲得每一位的數字,那麼我們也可以移動結果來填充每一步的值。
class Solution {public: uint32_t reverseBits(uint32_t n) { uint32_t answer; uint32_t int i; answer = 0; /*把一個unsigned int 數字1一直左移,直到它變成全0的時候,也就得到了該機器內unsigned int的長度*/ for (i = 1; i != 0; i <<= 1) { answer <<= 1; if (value & 1) { answer |= 1; } value >>= 1; } return answer; }};
這種方案將結果按照資料類型的位元進行移動,每次移動時判斷value的最後一位是否為1,如果為1,那麼在結果的最後一位添加1,如果不是,繼續移位。
這種方案效率會高很多,因為我們知道對於C++編譯器來講,位操作肯定會比加法操作效率高得多。
試想一下,我們還有沒有更好的方案呢,答案當時是肯定的。
http://graphics.stanford.edu/~seander/bithacks.html
在斯坦福的這篇文章裡面介紹了眾多有關位操作的奇思妙想,有些方法的確讓人稱讚,其中對於位翻轉有這樣的一種方法,將數位位按照整塊整塊的翻轉,例如32位分成兩塊16位的數字,16位分成兩個8位進行翻轉,這樣以此類推知道只有一位。
對於一個8位元字abcdefgh來講,處理的過程如下
abcdefgh -> efghabcd -> ghefcdab -> hgfedcba
class Solution {public: uint32_t reverseBits(uint32_t n) { n = (n >> 16) | (n << 16); n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8); n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4); n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2); n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1); return n; }};
這種方法的效率為O(log sizeof(int))。
不帶正負號的整數翻轉函數實現reverse_bits(unsigned int value)