有简单版的一道题:一组数中有一个是成单出现的,其余是成双出现的,问那个数是成单出现的。
计算机中的运算时二进制运算,因此有位运算的出现。而这道题主要是考察异或交换律
异或:同为相反为1,相同为0 例如 1^0=1 0^1=1 1^1=0 0^0=0
比如:数组 a[]:1 2 1 初始sum=1 用sum记录3次异或值:
第一次:0^1=1
第二次:01^10=11
第三次:11^01=10
当数组a[]:2 1 2 3 3 时:
同理,这个太多了我就懒得写了(●’◡’●)
通过异或可以找出一个成单的数。
现在题目是:一个整型数组 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 <= nums <= 10000
题目链接
有一种方法就是把数组分为2组,在每一组里面找到那个成单的数。答案为a,b;
- 把数组里面所有的数异或一遍 (得出来的异或值是两个成单数的异或值,也就是a^b=sum)
- 把sum和-sum进行与运算(k=sum&(-sum) k保留sum的最后一个1,通过这个1我们来进行分类。两个数相同的一定回到一组,同时a,b回分到不同的两组)
- 遍历分组
- 得到答案
分组关键:两个数位不同为1,那么找到sum中任意一个1,那就可以确定a,b的分组。
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int sum = 0;
int n=nums.size();//
for (int i = 0; i < n; i++) {
sum ^= nums[i];
}
int k = sum & (-sum);//分为两组的关键
int a = 0;
int b = 0;
for (int num:nums) {
if (num & k) {//分组策略
a ^= num;
}
else {
b ^= num;
}
}
return {a,b};//返回每组成单的值
}
};