190. 颠倒二进制位
要求:颠倒给定的 32 位无符号整数的二进制位。
例如:
输入: 43261596
二进制数据: 00000010100101000001111010011100
输出: 964176192
二进制数据: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
解题:
大致思路就是将二进制数不停的交换位置,合并。最后得到结果。
例如:0111 1001 0010 1101 0011 1101 1111 1010
每16位一组交换
1.1. 左边16位右移16位
0000 0000 0000 0000 0111 1001 0010 1101
1.2. 右边16位左移16位
0011 1101 1111 1010 0000 0000 0000 0000
合并(或运算):
0011 1101 1111 1010 0111 1001 0010 1101
所以:每16位一组交换公式:n = n >>> 16 | n << 16
-
每8位一组交换:从左至右:第一个8位,跟第二个8位交换;第三个8位跟第四个8位交换
因为合并结果就是要保证合并前与合并后非0位置的值保持不变,那么就要保证另一组相应位置为0。例如:0110 与 xxxx合并结果为0110,那么xxxx就一定是0000
反向推导过程:
2.1. 本次交换结果:
1111 1010 0011 1101 0010 1101 0111 1001
合并前2组数据:
1111 1010 0000 0000 0010 1101 0000 0000
0000 0000 0011 1101 0000 0000 0111 1001
2.2. 因为是每8位一组交换,所以对于“1111 1010 0000 0000 0010 1101 0000 0000”
右移8位前应该是:
0000 0000 1111 1010 0000 0000 0010 1101
那么由步骤1结果“0011 1101 1111 1010 0111 1001 0010 1101” 变成 “0000 0000 1111 1010 0000 0000 0010 1101”的方式可以使用位与运算
0011 1101 1111 1010 0111 1001 0010 1101 与 0000 0000 1111 1111 0000 0000 1111 1111
即:0011 1101 1111 1010 0111 1001 0010 1101 & 0x00ff00ff2.3. 因为是每8位一组交换,所以对于“0000 0000 0011 1101 0000 0000 0111 1001”
左移8位前应该是:
0011 1101 0000 0000 0111 1001 0000 0000
那么由步骤1结果“0011 1101 1111 1010 0111 1001 0010 1101” 变成 “1111 1010 0000 0000 0010 1101 0000 0000”的方式可以使用位与运算
0011 1101 1111 1010 0111 1001 0010 1101 与 1111 1111 0000 0000 1111 1111 0000 0000
即:0011 1101 1111 1010 0111 1001 0010 1101 & 0xff00ff00所以:每8位一组交换公式:
n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >>> 8)
每4位一组交换:从左至右:第一个4位,跟第二个4位交换;第三个4位跟第四个4位交换;第五个5位跟第六个4位交换;第七个4位跟第八个4位交换
重复步骤2推到过程,得知
每4位一组交换公式:n = ((n & 0000 1111 0000 1111 0000 1111 0000 1111) << 4) | ((n & 1111 0000 1111 0000 1111 0000 1111 0000) >>> 4) 即n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >>> 4)
每2位一组交换:从左至右:1(2) 交换 2(2); 3(2) 交换 4(2); 5(2) 交换 6(2); 7(2) 交换 8(2); 9(2) 交换 10(2); 11(2) 交换 12(2); 13(2) 交换 14(2); 15(2) 交换 16(2);
重复步骤2推到过程,得知
每2位一组交换公式:n = ((n & 0011 0011 0011 0011 0011 0011 0011 0011) << 2) | ((n & 1100 1100 1100 1100 1100 1100 1100 1100) >>> 2) 即n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >>> 2)
每1位一组交换:第一位跟第二位交换,第三位跟第四位交换;...... 第31位跟第32位交换
重复步骤2推到过程,得知
每1位一组交换公式:n = ((n & 0101 0101 0101 0101 0101 0101 0101 0101) << 2) | ((n & 1010 1010 1010 1010 1010 1010 1010 1010) >>> 2) 即n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >>> 1)
最终交换公式:
n = n >>> 16 | n << 16
n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >>> 8)
n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >>> 4)
n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >>> 2)
n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >>> 1)
java代码见github:190. 颠倒二进制位
链接:https://github.com/skyjilygao/sky-leetcode/blob/master/src/main/java/cn/skyjilygao/leetcode/ReverseBits.java