题目一
力扣:190. 颠倒二进制位
思路
常规
1、所谓颠倒,就是把原来的最右面的位数放在最左面
2、所以我们对原串,每次都 &1 取出最右面的位,再 | 进入答案即可
3、每次答案<<,原数>>即可。
细节
一定要注意,答案,应该先移位,流出地方,再进行 | 运算。
进阶(分治法)
1、我们想,所谓的整体颠倒,我们把32长度的串,从中间劈开,把右面的部分放在左半部分前面,不就得了。
2、但是这两部分内部必须得是颠倒过了的,然后借助递归的思路,逐渐二分。
3、所以,先颠倒长度为2的串,每两个颠倒了,再颠倒长度*2,再次执行,直到颠倒长度=32。
4、再加之这是位运算,各个位之间互不打扰,互不影响,所以各个长度的颠倒,在各个位之间可以并行,所以只需要执行5次即可得到答案
颠倒示例:
代码
常规
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t ans = 0;
for (int i = 0; i < 32; i++) {
ans <<= 1;//这里相当于往一个数字上进行拼数,先移位,留出位置,再|
ans |= (n & 1);
n >>= 1;
}
return ans;
}
};
所有代码均以通过力扣测试
(经过多次测试最短时间为):
进阶
class Solution {
private:
const uint32_t M1 = 0x55555555; // 01010101010101010101010101010101
const uint32_t M2 = 0x33333333; // 00110011001100110011001100110011
const uint32_t M4 = 0x0f0f0f0f; // 00001111000011110000111100001111
const uint32_t M8 = 0x00ff00ff; // 00000000111111110000000011111111
public:
uint32_t reverseBits(uint32_t n) {
n = ((n&M1) << 1) | (n >> 1 & M1);//注意优先级,<< 高于 &
n = ((n&M2) << 2) | (n >> 2 & M2);
n = ((n&M4) << 4) | (n >> 4 & M4);
n = ((n&M8) << 8) | (n >> 8 & M8);
return n >> 16 | n << 16;
}
};
所有代码均以通过力扣测试
(经过多次测试最短时间为):
题目二
力扣:191. 位1的个数
思路
常规
直接32位逐位统计1的个数即可
进阶
我们只要1的个数,所以0无意义,所以我们通过 n&(n-1)的方法,每算一次就干掉一个1,就可以跳过无用的0。
代码
常规
class Solution {
public:
int hammingWeight(uint32_t n) {
int ans = 0;
for (int i = 0; i < 32; i++) {
ans += n & 1;
n >>= 1;
}
return ans;
}
};
所有代码均以通过力扣测试
(经过多次测试最短时间为):
进阶
class Solution {
public:
int hammingWeight(uint32_t n) {
int ans = 0;
while (n > 0) {//我只想知道1出现的次数,所以和0没关系,所以把无意义的0越过去
n = n & (n - 1);//每次算完都会干掉1个1,起到了越过0的作用
ans++;
}
return ans;
}
};
所有代码均以通过力扣测试
(经过多次测试最短时间为):