有1个数字只出现一次,其余数字均出现2次
思想:使用异或,遍历数组,两两异或,即是最终的答案
- 时间复杂度:O(n)
找出缺失的数字
给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
思想:采用异或
- 数组内的所有元素先异或一次
- step1的结果在与 0~list.size() 每个数字异或一次
- 缺失的那个数字必然只被异或1次,其余数字参与了2次异或,最终的结果就是那个缺失的数字
有1个数字只出现一次,其余数字均出现3次
思想1:将每个数字看成32个bit位,对每一位,遍历整个数组,统计数组中该位为1的个数,当个数%3不为0时,该位为有效位
最终32位中的有效位组成的数字,即是只出现一次的数字
- 该方法为求解此类问题的通用方法
- 时间复杂度O(32n)
int find_num(int* nums, int len)
{
int ret = 0;
for (int i = 0; i < 32; i++)
{
int mask = 1 << i;
int cnt = 0;
for (int j = 0; j < len; j++)
{
if ((nums[j] & mask) != 0)
{
cnt++;
}
}
if (cnt % 3 != 0)
{
ret |= mask;
}
}
return ret;
}
思想2:设置3个变量 个人感觉不是很好想到
- 位为1的位置,出现的次数超过1次 (more_one)
- 位为1的位置,出现的次数为奇数次 (odd)
- 微为1的位置,出现3次
- 时间复杂度O(n)
int find_num(int* nums, int len)
{
int more_one = 0;
int odd = 0;
int three = 0;
for (int i = 0; i < len; i++)
{
more_one = more_one | (odd & nums[i]);
odd = odd ^ nums[i];
three = more_one & odd;
// 出现三次的位置 清空
more_one = more_one & (~three);
odd = odd & (~three);
}
// 根据题目,最后出现奇数次的,到此为止,只出现了1次
return odd;
}
有2个数字只出现1次,其余数字均出现2次
思路:
- 遍历所有元素求异或,其结果为2个只出现1次的数字的异或值
- 随便找第一步中值二进制位为1的位置,按照该位是否为1,将原始数组分为2个数组
- 分别对上面求出的两个数组中的元素求异或即可得到2个只出现1次的数字
所有小写英文字母a~e,求其顺序子集
eg:{a},{ab},{ac},{abc}
思路:
将a~e这5个英文字母组合,看成[00001-11111]区间内的数字
每一个数字,即对应一套子集
比特计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
思路:奇数和偶数分开来看
- 对偶数2n,2n的中1出现的次数与n中1出现的次数相同
- 对奇数2n+1,二进制的最后一位肯定是1,2n+1中1出现的次数比n中1出现的次数多1
std::vector calcbits(int num)
{
std::vector<int> res;
res.emplace_back(0);
if (num == 0)
{
return res;
}
for (int i = 1; i <= num; i++)
{
if (i % 2 == 0)
{
res.emplace_back(res[i / 2]);
}
else
{
res.emplace_back(res[i / 2] + 1);
}
}
return res;
}