有关位运算的操作符
>>
<<
&
|
^
~
常见位运算操作
给定一个数,确定它的二进制中第x位是0还是1
(n >> x) & 1;
将一个数n的二进制中第x位修改为1
n |= (1 << x)
将一个数n的二进制中第x位修改为0
n &= (~(1 << x))
提取一个数二进制中最右侧的1
n & (-n)
去掉一个数中二进制最右侧的1
n & (n-1)
异或运算律
- a ^ a = 0
- a ^ 0 = a
- a ^ b ^ c = a ^ (b ^ c)
191. 位1的个数 - 力扣(LeetCode)
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
示例 1:
输入: n = 00000000000000000000000000001011
输出: 3
解释: 输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:
输入: n = 00000000000000000000000010000000
输出: 1
解释: 输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:
输入: n = 11111111111111111111111111111101
输出: 31
解释: 输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
解题思路
n & (n-1)每次可以干掉二进制中最右侧的1
代码实现
class Solution {
public:
int hammingWeight(uint32_t n)
{
int ret = 0;
while(n != 0)
{
n &= n-1;
ret++;
}
return ret;
}
};
338. 比特位计数 - 力扣(LeetCode)
给你一个整数 n
,对于 0 <= i <= n
中的每个 i
,计算其二进制表示中 1
的个数 ,返回一个长度为 n + 1
的数组 ans
作为答案。
示例 1:
输入: n = 2
输出: [0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:
输入: n = 5
输出: [0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
解题思路
利用n&(n-1)从最高位开始统计位1的个数,将结果存放到vector中即可。时间复杂度O(n^2)
代码实现
class Solution
{
public:
vector<int> countBits(int n)
{
vector<int> ans(n+1);
while(n >= 0)
{
int ret = 0,tmp = n;
while(tmp != 0)
{
tmp = tmp & (tmp-1);
ret++;
}
ans[n--] = ret;
}
return ans;
}
};
461. 汉明距离 - 力扣(LeetCode)
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
给你两个整数 x
和 y
,计算并返回它们之间的汉明距离。
示例 1:
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
解题思路
异或后求二进制位1的个数即可
代码实现
class Solution
{
public:
int hammingDistance(int x, int y)
{
//异或,求异或后二进制1的个数即可
int ret = x ^ y;
int sum = 0;
while(ret != 0)
{
ret &= (ret-1);
sum++;
}
return sum;
}
};
136. 只出现一次的数字 - 力扣(LeetCode)
给你一个 非空 整数数组 nums
,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入: nums = [2,2,1]
输出: 1
示例 2 :
输入: nums = [4,1,2,1,2]
输出: 4
示例 3 :
输入: nums = [1]
输出: 1
解题思路
- a^0 = a;
- a^a = 0;
- abc = a(bc)
- 41212 = 4(11)(22)
- 空间复杂度要求O(n) 不能使用哈希表
代码实现
class Solution
{
public:
int singleNumber(vector<int>& nums)
{
//a^0 = a;
//a^a = 0;
//a^b^c = a^(b^c)
//4^1^2^1^2 = 4^(1^1)^(2^2)
int ret = 0;
for(auto &e : nums)
{
ret ^= e;
}
return ret;
}
};
面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode)
实现一个算法,确定一个字符串 s
的所有字符是否全都不同。
示例 1:
输入: s = "leetcode"
输出: false
示例 2:
输入: s = "abc"
输出: true
限制:
0 <= len(s) <= 100
s[i]
仅包含小写字母- 如果你不使用额外的数据结构,会很加分。
解题思路
- 哈希表。
- 字符串中仅包含小写字母,使用数组模拟哈希表即可。时间复杂度O(n);
- 位运算
- 位图思想 26个比特位即可(一个字节即可)
代码实现
class Solution
{
public:
bool isUnique(string astr)
{
if(astr.size() > 26)
{
return false;
}
//哈希表
// int hash[26] = {0};
// for(size_t i = 0; i < astr.size(); ++i)
// {
// hash[astr[i] - 'a']++;
// }
// for(auto e : hash)
// {
// if(e >= 2 ) return false;
// }
// return true;
// 位图
int bit_map = 0;
for(auto e : astr)
{
int index = e - 'a';
//判断是否在位图中。
if((bit_map >> index) & 1 == 1) return false;
//加入位图
bit_map |= (1 << index);
}
return true;
}
};
268. 丢失的数字 - 力扣(LeetCode)
给定一个包含 [0, n]
中 n
个数的数组 nums
,找出 [0, n]
这个范围内没有出现在数组中的那个数。
示例 1:
输入: nums = [3,0,1]
输出: 2
解释: n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 2:
输入: nums = [0,1]
输出: 2
解释: n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 3:
输入: nums = [9,6,4,2,3,5,7,0,1]
输出: 8
解释: n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。
示例 4:
输入: nums = [0]
输出: 1
解释: n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。
解题思路
- 哈希表
- 高斯求和
- 异或运算符
class Solution
{
public:
int missingNumber(vector<int>& nums)
{
//哈希表
// int hash[10000] = {0};
// //存放到哈希表中
// for(size_t i = 0; i < nums.size();++i)
// {
// hash[nums[i]]++;
// }
// //遍历哈希表
// for(size_t i =0 ; i < 10000; i++)
// {
// if(hash[i] ==0 ) return i;
// }
// return 0;
//高斯求和
// size_t n = nums.size();
// int sum = 0;
// for(size_t i = 0; i < n ; ++i)
// {
// sum += nums[i];
// }
// return ((n) * (n +1) / 2 ) - sum;
//位运算(异或运算律)
int ret = 0;
for(auto e : nums)
{
ret ^= e;
}
for(int i = 0; i < nums.size() + 1 ; ++i)
{
ret ^= i;
}
return ret;
}
};