------------------------------------------------------二刷2021/2/4------------------------------------------------------
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int tmp = 0;
for(int num : nums) {
tmp ^= num;
}
int digital = 1;
//寻找tmp为1即两个只出现一次数字不同的二进制位
while((tmp & digital) == 0) {
digital <<= 1;
}
int ans1 = 0 , ans2 = 0;
for(int num : nums){
if(num & digital) ans1 ^= num;
else ans2 ^= num;
}
return vector<int>{ans1, ans2};
}
};
while((tmp & digital) == 0) {
记得里面加括号,位运算优先级低于比较运算符
56-I
题目描述
思路 分组异或
假设题目里面只有一个唯一数字的时候,我们可以设一个0,逐次异或到数组结束
int ans= 0;
for(int num : nums) {
ans^= num;
}
return ans;
得到的结果就是那个唯一的数字。
ps:异或符号为^
原因有两个
1.相同的数字异或等于0
2.异或运算满足交换律
这两点自己试试就知道了
现在题目有两个数字怎么办? 思路很难想到,但是一旦知道就很容易记住
我们还是设一个0,逐次异或到数组结束,设得到的结果为temp
很明显是两个唯一数字相异或的结果。
那么对这个结果的数字的每位二进制进行分析,设temp
的某个位为 Ai
Ai = 1,两个数字该位不同
Ai = 0,两个数字该位相同
那么只需要找到Ai = 1,将所有的数字分成 Ai = 1组和 Ai = 0组,自然也会把两个唯一数字分卡,并且分的过程中成对的数字不会被拆散,对于这两组数字分别执行只有一个唯一数字的情况下的算法就可以得到解了。
唯一的难点在于怎么对于每个数字获得Ai的值呢
这里用一个dNum变量,初始值为1代表第一位,然后每次右移一位。 num ^ dNum 即是对应二进制位的值。
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int temp = 0;
for(int num : nums) {
temp ^= num;
}
int dNum = 1;
while((temp & dNum) == 0) dNum <<= 1;
int ans1 = 0, ans2 = 0;//0异或任何数等于该数
for(int num : nums){
if(num & dNum)
ans1 ^= num;
else ans2 ^= num;
}
return vector<int> {ans1,ans2};
}
};
时间复杂度O(n)
空间复杂度O(1)
56-II
题目描述
先试着想了一下异或和同或,发现完全没有思路,于是无脑哈希解一下。
解法 哈希表
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map <int,int> hash;
for(int num : nums) {
hash[num] ++;
}
for(int num : nums) {
if(hash[num] == 1)
return num;
}
return 0;
}
};
时间复杂度O(N)
空间复杂度O(N)
解法 位运算
拒绝反复造轮子
竟然是有限状态机,跳过!