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]
2、VS2019上运行
Krahets方法(位运算)
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int x = 0, y = 0, n = 0, m = 1;
for (int num : nums) // 1. 遍历异或
n ^= num;
while ((n & m) == 0) // 2. 循环左移,计算 m
m <<= 1;
for (int num : nums) { // 3. 遍历 nums 分组
if (num & m) x ^= num; // 4. 当 num & m != 0
else y ^= num; // 4. 当 num & m == 0
}
return vector<int> {x, y}; // 5. 返回出现一次的数字
}
};
int main() {
vector<int> nums = { 1, 2, 1, 3, 2, 5 };
Solution solution;
vector<int> result = solution.singleNumbers(nums);
cout << "Single Numbers: " << result[0] << " and " << result[1] << endl;
return 0;
}
Single Numbers: 3 and 5
3、解题思路
- 1、遍历数组nums,将所有数字进行异或运算并保存在变量n中。
nums中所有出现两次的数字进行异或运算,结果会相互抵消为0。
只出现一次的两个数字,在异或运算中会保留下来。 - 2、找到n中最低位的1,并将其保存在变量m中。
初始时,m为1(二进制为 0001)。
通过将m左移,每次左移一位,直到(n & m)不等于0,也就是找到n中最低位的1。
这个步骤的目的是将两个只出现一次的数字区分到不同的分组。 - 3、再次遍历数组nums,根据m的值将数字分为两组,并分别进行异或运算。
如果数字在m位上为1,将其归为一组。
如果数字在m位上为0,将其归为另一组。
这样,只出现一次的两个数字就被分到了不同的组中。 - 4、进行异或运算,得到两个只出现一次的数字。
对每个分组中的数字进行异或运算,得到两个结果:x和y。
x和y就是只出现一次的两个数字。 - 5、将x和y放入一个新的vector中,并作为结果返回。