class Solution {
public:
int hammingDistance(int x, int y) {
int res = abs(x) ^ abs(y);
int count = 0;
while(res)
{
//if(res & 1)
// count++;
res = res & (res - 1);
count++;
}
return count;
}
};
- 只出现一次的数字
- 丢失的数字
这道题出了可以用位运算来做,还可以通过求和来做。但是要注意,求和有溢出的风险,最好就是一边求和,一边做减法。 - 只出现一次的数字 III
两个收获:
1.最开始把 while((res&1)0) 写成得是 while(res&10),答案死活不对。因为优先级不对。
2.如何判断某个数的二进制表示中某一位是否为1.参看注释。
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int res = 0;
for(int x : nums)
res ^= x;
int pos = 1;
//while((res&1)==0) // == 的优先级高于&
//{
// pos++;
// res = res>>1;
//}
//cout << "pos: " << pos << endl;
//int flag = 1;
//while(--pos)
//{
// flag = flag << 1;
//}
// 上面的思路是先找出位置,再去构造这个数,实际上可以直接构造出这个数
while((res&1)==0) // == 的优先级高于&
{
pos <<= 1;
res = res>>1;
}
int num1 = 0, num2 = 0;
for(int x : nums)
{
if(pos & x) //判断x的第pos个数是否为1
num1 ^= x;
else
num2 ^= x;
}
return {num1, num2};
}
};
- 颠倒二进制位
位运算还是都加括号吧,看了评论区,好多人也都有这个问题。
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t ans = 0;
int run = 32;
while(run--) //注意这个地方不能是n,因为如果是n的话,有可能不能执行32次
{
ans = (ans<<1) + (n & 1);
n >>= 1;
}
return ans;
}
};
进阶解答一脸懵逼,看了这篇文章后终于清楚了。
- 不用额外变量交换两个数
a = a ^ b;
b = a ^ b;
a = a ^ b;
- 判断是否是2的幂
最直接的思路当然是把这个数一直除以二,每次都判断它的余数是否为0。复杂度为log(N)
另一个思路就是2的幂的二进制表示中只有一个数是1.所以,统计1的个数。
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n==0) // 第一次提交跪在了这儿
return false;
int count = 0;
while(n)
{
count += (n & 1);
if(count > 1)
return false;
n >>= 1;
}
return true;
}
};
上面的实现很复杂,利用性质,能有更简单的实现
n & (-n) : 得到 n 的位级表示中最低的那一位 1。
n & (n - 1) : 去除 n 的位级表示中最低的那一位 1。
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n<=0)
return false;
return (n & (n - 1)) == 0; // 加括号! 加括号! 加括号!
}
};
- 4的幂
这道题和上一道题的区别在于,4的幂中1在奇数位上。判断是否在奇数位上,可以这样写:n & 10101010101 != 0
但是C++中没有二进制表示,所以,有如下十六进制 表示:
0xaaaaaaaa = 10101010101010101010101010101010 左边有8个a,右边有32个0\1,偶数位为1,奇数位为0)
0x55555555 = 1010101010101010101010101010101 (偶数位为0,奇数位为1)
0x33333333 = 110011001100110011001100110011 (1和0每隔两位交替出现)
0xcccccccc = 11001100110011001100110011001100 (0和1每隔两位交替出现)
0x0f0f0f0f = 00001111000011110000111100001111 (1和0每隔四位交替出现)
0xf0f0f0f0 = 11110000111100001111000011110000 (0和1每隔四位交替出现)
所以,代码如下:
class Solution {
public:
bool isPowerOfFour(int n) {
if(n<=0 || (n & (-n))!=n)
return false;
return n & 0x55555555; //判断是否在奇数位上
}
int posOf1(int n)
{
int pos = 1;
while((n&1)==0)
{
pos++;
n >>= 1;
}
return pos;
}
};
- 交替位二进制数
评论区:将n右移一位后与n异或,结果全为1.
class Solution {
public:
bool hasAlternatingBits(int n) {
int num = n^(n>>1);
return ((num+1) & num) == 0;
}
};
- 求一个数的补码
任何一个数异或111111(位数和它本身相同)都会变为它的补码。 - 不使用运算符 + 和 - ,计算两整数 a 、b 之和
怎么解决负数的问题,还需要参考一下剑指offer。
class Solution {
public:
int getSum(int a, int b) {
int x = a ^ b;
int y = (unsigned int)(a & b);
while(y)
{
y <<= 1;
int temp = x; //这个地方如果不事先保存x的值的话是不对的。
x = x ^ y;
y = (unsigned int)(temp & y);
}
return x;
}
};
-
最大单词长度乘积
收获:利用位掩码判断两个字符串是否含有相同的字母。 -
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
我的解答:
主要是通过找规律
class Solution {
public:
vector<int> countBits(int num) {
vector<int> ans(num+1, 0);
int gap = 1;
int start = 0;
int pos = 1;
while(pos < num+1)
{
int nextGap = 2 * gap;
while(gap-- && (pos < num+1))
{
ans[pos++] = 1 + ans[start++];
}
start = 0;
gap = nextGap;
}
return ans;
}
};
位运算:
利用 x&(x-1)能消去最右边的1,所以x的1的数量就是x&(x-1)中1的数量加1.