题目1:
一个整型数组 nums里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
解法一:用unordered_map解决,但是由于题目说要求空间复杂度为O(1),因此这种方法不可取
vector<int> singleNumbers(vector<int>& nums)
{
vector<int> vec;
unordered_map<int, int> counts;
for (auto& x : nums)
{
counts[x]++;
}
for (auto& x : counts)
{
if (x.second == 1)
{
vec.push_back(x.first);
}
}
return vec;
}
解法二:参考官方题解
利用位运算解决
vector<int> singleNumbers(vector<int>& nums)
{
//先将所有元素异或。最后剩下的数是只出现一次的数字num1,num2的异或
int k = 0; // 0^x = x
for (int i : nums) //所有数字异或
k ^= i;
int mask = 1;
while ((k & 1) != 1)
{
//从后往前找到最低位的1;
k = k >> 1;
mask = mask << 1;
}
int num1 = 0, num2 = 0;
//用这个mask就可以把两个数区分开,
for (int i : nums)
{
if ((i & mask) != 0) num1 ^= i; // mask指定的那一位是num1,num2的不同
else num2 ^= i;
}
return { num1,num2 };
}
题目2:
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例 1:
输入:nums = [3,4,3,3] 输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7] 输出:1
同样的也可以用unordered_map
来解决,但是空间复杂度太高,所以我们还是考虑用位运算来解决。
(参考力扣题解)
用一个32位数组统计二进制位出现次数,对3取余,可以得到目标数字每个位置的数字
int singleNumber(vector<int>& nums)
{
int bits[32] = { 0 }, res = 0; //存放各位1出现的次数
for (int num : nums) //统计二进制位
{
for (int i = 31; i >= 0; --i)
{
bits[i] += num & 1;
num >>= 1;
}
}
for (int n : bits) //还原
{
res <<= 1;
res += n % 3; //n % 3表示目标数字的二进制位,因为其他数字都是3的倍数次数出现的
}
return res;
}
除此之外还可以用排序:
int singleNumber(vector<int>& nums)
{
sort(nums.begin(), nums.end());
for (auto i = 0; i < nums.size() - 2; i += 3)//每三个数检查一次
{
if (nums[i] != nums[i + 2]) //很好理解,比如0,0,0,1,1,3,3,3
return nums[i]; //第一次检查,nums[0] == nums[2];i+2,检查下一组
} //第二次检查,nums[3] != nums[5],返回nums[3]。
return nums.back();
}