解法:
方法一:每次把 res 左移,把 n的二进制末尾数字,拼接到结果 res 的末尾。然后把 n 右移。
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t res = 0;
for(int i = 0; i < 32; ++i){
res = (res << 1) | (n & 1); //(n&1),n位与1,得n的最低位,再或res,既将n的最低为给res
n >>= 1; //n右移,
}
return res;
}
};
方法二:分治法,把数字分为两半,然后交换这两半的顺序;然后把前后两个半段都再分成两半,交换内部顺序……直至最后交换顺序的时候,交换的数字只有 1 位。引用图片。
示例: 假设n二进制为:1011 0111 0011 1001 0011 1111 0110 1010 n = (n >> 16) | (n << 16); n >>> 16 就是左边16位被移动到了右侧, n << 16 就是右边16位被移动到了左侧,又 | 在了一起,所以,n变成了 0011 1111 0110 1010 1011 0111 0011 1001 ((n & 0xff00ff00) >> 8); 左侧开始算0~7位,保留;8~15位,全变0;16~23位,保留;24~31位,全变0,n此时为0011 1111 0000 0000 1011 0111 0000 0000,然后统一右移8位,n为0000 0000 0011 1111 0000 0000 1011 0111 ((n & 0x00ff00ff) << 8); 左侧开始算0~7位,全变0;8~15位,保留;16~23位,全变0;24~31位,保留此时n为0000 0000 0110 1010 0000 0000 0011 1001,然后左移8位,n为0110 1010 0000 0000 0011 1001 0000 0000 ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8) 就是n的0~7位和8~15位交换了,16~23位和24~31位交换了,n为0110 1010 0011 1111 0011 1001 1011 0111 也就是说,整个过程是n的左16位,和右16位交换 n的左16位的内部,左8位和右8位交换;n的右16位的内部,左8位和右8位交换 接下来的一行,其实是,从左边开始算,0~7位内部,左4和右4交换;8~15位,左4和右4交换;... ((n & 0xf0f0f0f0) >> 4) n为 0000 0110 0000 0011 0000 0011 0000 1011 ((n & 0x0f0f0f0f) << 4) n为 1010 0000 1111 0000 1001 0000 0111 0000 ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4) n为 1010 0110 1111 0011 1001 0011 0111 1011 接下来的一行,其实是,从左边开始算,0~3位内部,左2和右2交换;4~7位,左2和右2交换; 最后的一行,其实是,从左边开始算,0~1位内部,左1和右1交换;2~3位,左1和右1交换; 在这里就顺便说一下常用的二进制数: 0xAAAAAAAA=10101010101010101010101010101010 0x55555555 = 1010101010101010101010101010101(奇数位为1,以1位为单位提取奇偶位) 0xCCCCCCCC = 11001100110011001100110011001100 0x33333333 = 00110011001100110011001100110011(以“2位”为单位提取奇偶位) 0xF0F0F0F0 = 11110000111100001111000011110000 0x0F0F0F0F = 1111000011110000111100001111(以“8位”为单位提取奇偶位) 0xFFFF0000 =11111111111111110000000000000000 0x0000FFFF = 1111111111111111(以“16位”为单位提取奇偶位)
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
n = (n >> 16) | (n << 16);
n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8); //n的0~7位和8~15位交换了,16~23位和24~31位交换了
n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4);
n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2);
n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1);
return n;
}
};
136.只出现一次的数字
解法:用set容器开辟了额外的空间,
根据题解思路,异或运算有如下三条性质:
1.任何数和0做异或运算,结果仍是原来的数;
2.任何数和其自身做异或运算,结果是0;
3.异或运算满足交换律和结合律。
class Solution {
public:
int singleNumber(vector& nums) {
unordered_set s;
for(int i = 0; i < nums.size(); i++){
if(s.find(nums[i]) == s.end()){ //如果set容器内不存在该数,则加入,否则删除
s.insert(nums[i]);
}
else{
s.erase(nums[i]);
}
}
unordered_set::iterator it = s.begin();
return *it;
}
};
//由于交换律的存在,只存在一个只出现一次的值,故其他的值都可以通过异或自己本身得到0,然后0与唯一的那个数异或得到只出现一次的那个数。
class Solution {
public:
int singleNumber(vector& nums) {
// 异或
int res = nums[0];
for (int i = 1; i < nums.size(); i++) {
res ^= nums[i]; //由于交换律的存在,只存在一个只出现一次的值,故其他的值都可以通过异或自己本身消除,得到唯一的值
}
return res;
}
};



