137. 只出现一次的数字 II
算法掌握:
- 位运算(异或 ^, 取反~,与运算&)
- 常见的位运算操作:
- 与运算(&):对两个操作数的每个对应比特位执行 AND 运算,只有当两个位都为 1 时,结果位才为 1。
- 或运算(|):对两个操作数的每个对应比特位执行 OR 运算,只要其中一个位为 1,结果位就为 1。
- 异或运算(^):对两个操作数的每个对应比特位执行 XOR 运算,当两个位不同时结果位为 1,否则为 0。
- 取反运算(~):反转操作数的每个位,将 0 变为 1,将 1 变为 0。
- 左移运算(<<):将操作数的比特位向左移动指定的位数,低位补 0。
- 右移运算(>>):将操作数的比特位向右移动指定的位数,高位补符号位(负数补 1,正数补 0)。
解题思路:
本题如果不考虑 线性时间复杂度的算法且使用常数级空间来解决此问题的话, 直接用hash表存储判读即可,本题还是和 136. 只出现一次的数字 差不多的思路,可以先观看 leetcode每日一题 2023/10/14 这篇文章,不同的是判断的条件不一样,我们可以将一串数展开为2进制,相同得三个数的对应二进制位的数都是三倍,将数的每一位的个数进行判断即可
例如 [2, 2, 3, 2]
我们多尝试几组数据来验证 [3, 4, 4, 4, 5, 5, 5]
位运算性质
- 异或运算:
x ^ 0 = x,x ^ 1 = ~x (取反) - 与运算:
x & 0 = 0,x & 1 = x % 2 (取最低位) - 位移运算:
x >> i = x / (i * 2),(x >> i) & 1 -> (取出第i位的数) - 或运算:
for i -> 32: x |= (1 << i) (将每一位的值合并)
java code:
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
// int型是32位,将每一位取出计算
for(int i = 0; i < 32; i++){
int cnt = 0;
for(int num : nums){
cnt += (num >> i) & 1;
}
if(cnt % 3 > 0) res |= (1 << i);
}
return res;
}
}
c++ code
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for(int i = 0; i < 32; i++){
int cnt = 0;
for(int num : nums) cnt += (num >> i) & 1;
if(cnt % 3) res |= (1 << i);
}
return res;
}
};