目录
题目描述
给定一个32位无符号数,将其从最高位反转至最低位,最低为反转至最高位,如abcd,反转为dcba
基本思路
开辟一个临时变量,循环将待反转数的最低位取出,放置在临时变量的最高位;次低位放置在临时变量的次高位,依次执行,时间复杂度位O(32)
uint32_t reverseBits(uint32_t n) {
uint32_t r = 0; // 临时变量
for(int i=0; i<32; i++){
int bit = n & (1 << i); //取低位
if(bit) {
r = r | (1 << (31-i)); // 放置在高位
}
}
return r;
}
优化思路
利用分治的思想,考虑字符abcd,我们反转的过程,可以是这样的:将abcd对半开,将ab放在cd的位置,将cd放在ab的位置;然后依次反转ab和cd;也就是反复划分子串并反转子串,直至递归的最终情况,只剩2个字符,将这两个字符反转即可
对于一个32位的无符号数,需要进行5次交换:2个16位的子串、4个8位的子串、8个4位的子串、16个2位的子串、以及最后的两两交换。从上到下交换和从下到上的交换结果是一样的,因此我们可以先两两交换
利用掩码可以实现快速交换,例如两两交换:我们可以左移1位将原来偶数位的交换至奇数位,右移一位将原来奇数位的交换至偶数位;利用掩码的逻辑与运算将非需要的位置0,再利用掩码的逻辑或运算将两个交换的半串拼接
假设我们要交换无符号数n,掩码可以设置为010101010101010101010101010101,代码可以这样写:
uint32_t mask1 = 0x55555555; // 设置掩码
n1 = ((n >> 1) & mask1) // 右移将偶数位移至奇数位,掩码消除偶数位
n2 = ((n & mask1) << 1); // 掩码消除偶数位,左移将奇数位移至偶数位
n = n1 | n2; // 逻辑或运算将奇数位与偶数位合并
当然也可以写简洁一点:
n = ((n >> 1) & mask1) | ((n & mask1) << 1);
对于交换2位子串、4位子串等,也是类似的思路,只是左右移的位数和掩码有所区别;具体的可以看代码实现
代码实现
uint32_t reverseBits(uint32_t n) {
// 掩码
uint32_t mask1 = 0x55555555; // 01010101010101010101010101010101
uint32_t mask2 = 0x33333333; // 00110011001100110011001100110011
uint32_t mask4 = 0x0f0f0f0f; // 00001111000011110000111100001111
uint32_t mask8 = 0x00ff00ff; // 00000000111111110000000011111111
// 依次交换
n = ((n >> 1) & mask1) | ((n & mask1) << 1);
n = ((n >> 2) & mask2) | ((n & mask2) << 2);
n = ((n >> 4) & mask4) | ((n & mask4) << 4);
n = ((n >> 8) & mask8) | ((n & mask8) << 8);
n = (n >> 16) | (n << 16);
return n;
}