题目一
一个整型数组 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]
题解思路:分组异或
- 先对所有数字进行一次异或,得到两个出现一次的数字的异或值。
- 在异或结果中找到任意为 1 的位。
- 根据这一位对所有的数字进行分组。
- 在每个组内进行异或操作,得到两个数字。
复杂度分析
- 时间复杂度:O(n),我们只需要遍历数组两次。
- 空间复杂度:O(1),只需要常数的空间存放若干变量。
代码实现:
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int ret = 0, sz = nums.size();
for(int n : nums){
ret ^= n;
}
int div = 1;
while((div & ret) == 0){
div <<= 1;
}
int a = 0, b = 0;
for(int n : nums){
if(div & n){
a ^= n;
}
else{
b ^= n;
}
}
return vector<int>{a, b};
}
};
题目二
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1
题解思路:
方法一:排序
代码实现:
class Solution {
public:
int singleNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
for(auto i = 0; i < nums.size()-3; i += 3) //每三个数检查一次
{
if(nums[i] != nums[i+2]) //很好理解,比如0,0,0,1,3,3,3
return nums[i]; //第一次检查,nums[0] == nums[2];i+2,检查下一组
} //第二次检查,nums[3] != nums[5],返回nums[3]。
return nums.back();
}
};
方法二:hashmap
- 统计所有数字的次数,采用key : value的方式存在哈希表中
- 扫描哈希表,找出只出现一次的那个数字
代码实现:
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int, int> m;
for(int n : nums){
m[n]++;
}
int res = 0;
for(auto i : m){
if (i.second == 1) {
res = i.first;
break;
}
}
return res;
}
};
方法三:位运算
- 值得注意的是:如果某个数字出现3次,那么这个3个数字的和肯定能被3整除,则其对应二进制位的每一位的和也能被3整除
- 统计数组中每个数字的二进制中每一位的和,判断该和是否能被3整除。
- 若可以,则只出现一次的数字的二进制数中那一位为0,否则为1
代码实现:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for(int i = 0; i < 32; ++i){
int cnt = 0;
for(int n : nums){
// n & 1 << i 的值大于0即为真
if(n & (1 << i)) cnt++;
}
// 构造只出现一次的那个数字,采用异或的方法生成二进制中的每一位
if(cnt % 3 == 1) res ^= (1 << i);
}
return res;
}
};
如有帮助到您,可以多多点赞、评论鼓励哟~~~