137. 只出现一次的数字 II - 力扣(LeetCode)
这题的进阶:LeetCode第 136 题:只出现一次的数字(C++)_zj-CSDN博客
哈希表
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int, int> m;
for(int i = 0; i < nums.size(); ++i)
++m[nums[i]];
for(auto c : nums){
if(m[c] == 1) return c;
}
return 0;
}
};
倍数计算
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_set<int> s;
long sum = 0;
for(int i = 0; i < nums.size(); ++i){
sum += nums[i];
s.insert(nums[i]);
}
long val = accumulate(s.begin(), s.end(), long(0));
return (3*val - sum)/2;
}
};
位运算
考虑数字的二进制形式,对于出现三次的数字,各二进制位出现的次数都是 3 的倍数。所以,把所有数字展开为二进制形式,统计所以数字的二进制中1出现的次数,然后对3取模,剩下的就是只出现一次的数字,如图(来自:137. 只出现一次的数字 II(有限状态自动机 + 位运算,清晰图解)):
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for(int i = 0; i < 32; ++i){
int cnt = 0 ;
for(auto num : nums){
cnt += (num >> i) & 1;
}
res ^= (cnt%3)<<i;//<<的优先级高于 ^=
}
return res;
}
};
对比上图:
i = 0时,最右边累计1的个数,cnt = 4, 4 % 3 = 1,1就是目标数(只出现一位的那个数)的最右边的位(右起第一位)。
i = 0时,右起第二位累计1的个数,cnt = 3, 3 % 3 = 0,0就是目标数(只出现一位的那个数)的右起第二位。
。。。
依次计算即可。
这种方法可以推广到某个数出现一次,其他数出现k次的情况,如果k为偶数,直接异或运算就行,如果k为奇数,将本方法中的对3取模改为对k取模即可。
逻辑位运算
当年数字逻辑电路的知识了,都忘了。可以看这个题解: