Reverse Bits
Description:
Reverse bits of a given 32 bits unsigned integer.
For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as00111001011110000010100101000000).
Follow up:
If this function is called many times, how would you optimize it?
Related problem: Reverse Integer
Code1:
1 uint32_t reverseBits(uint32_t n) { 2 uint32_t result = 0; 3 for (int i = 0; i < 32; ++i) 4 { 5 result = (result << 1) | (n & 1); 6 n = n>>1; 7 } 8 }
PS:当把32改成8*sizeof(uint32)或者8*sizeof(int)时得到的结果不正确,不懂为什么?
Code2:
uint32_t reverseBits(uint32_t n) { n = ((n >> 1)&0x55555555) | ((n & 0x55555555) << 1); n = ((n >> 2)&0x33333333) | ((n & 0x33333333) << 2); n = ((n >> 4)&0x0F0F0F0F) | ((n & 0x0F0F0F0F) << 4); n = ((n >> 8)&0x00FF00FF) | ((n & 0x00FF00FF) << 8); n = (n >> 16) | (n << 16); }
PS:这段代码在VS下能运行,但在leetCode上运行得到的结果是错误的。最近leetCode好像总是会出现一些墨明棋妙的问题。
解法2有点类似于归并算法,通过不断地进行两两逆序来实现整个数据的逆序.
我们知道如何对字符串求逆序,现在要求计算二进制的逆序,如数34520用二进制表示为:
10000110 11011000
将它逆序,我们得到了一个新的二进制数:
00011011 01100001
它即是十进制的7009。
回顾下字符串的逆序,可以从字符串的首尾开始,依次交换两端的数据。在二进制逆序我们也可以用这种方法,但运用位操作的高低位交换来处理二进制逆序将会得到更简洁的方法。类似于归并排序的分组处理,可以通过下面4步得到16位数据的二进制逆序:
第一步:每2位为一组,组内高低位交换
10 00 01 10 11 01 10 00
-->01 00 10 01 11 10 01 00
第二步:每4位为一组,组内高低位交换
0100 1001 1110 0100
-->0001 0110 1011 0001
第三步:每8位为一组,组内高低位交换
00010110 10110001
-->01100001 00011011
第四步:每16位为一组,组内高低位交换
01100001 00011011
-->00011011 01100001
对第一步,可以依次取出每2位作一组,再组内高低位交换,这样有点麻烦,下面介绍一种非常有技巧的方法。先分别取10000110 11011000的奇数位和偶数位,空位以下划线表示。
原 数 10000110 11011000
奇数位 1_0_0_1_ 1_0_1_0_
偶数位 _0_0_1_0 _1_1_0_0
将下划线用0填充,可得
原 数 10000110 11011000
奇数位 10000010 10001000
偶数位 00000100 01010000
再将奇数位右移一位,偶数位左移一位,此时将这两个数据相或即可以达到奇偶位上数据交换的效果了。
原 数 10000110 11011000
奇数位右移 01000001 01000100
偶数位左移 00001000 10100000
相或得到 01001001 11100100
可以看出,结果完全达到了奇偶位的数据交换,再来考虑代码的实现——
取x的奇数位并将偶数位用0填充用代码实现就是x & 0xAAAA
取x的偶数位并将奇数位用0填充用代码实现就是x & 0x5555
因此,第一步就用代码实现就是:
x = ((x & 0xAAAA) >> 1) | ((x & 0x5555) << 1);
类似可以得到后三步的代码。
1 unsigned int reverseBits(unsigned int n) { 2 //n为32位时的代码 3 n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); 4 n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); 5 n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); 6 n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); 7 n = (n>>16)|(n<<16); 8 }