Leetcode剑指Offer刷题指南:
解法:分组异或
class Solution {
public int[] singleNumbers(int[] nums) {
//遍历 nums 执行异或
int n = 0, m = 1, x = 0, y = 0;
for (int num : nums) {
n ^= num;
}
//此时 n = x ^ y
//循环左移,计算 m
while ((n & m) == 0) {
m <<= 1;
}
//遍历 nums 分组
for (int num : nums) {
if ((num & m) != 0) {
//当 num & m != 0
x ^= num;
} else {
//当 num & m == 0
y ^= num;
}
}
//返回出现一次的数字
return new int[]{x, y};
}
}
剑指 Offer 56 - II. 数组中数字出现的次数 II
解法一:hashmap
class Solution {
public int singleNumber(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int n : nums) {
map.put(n, map.getOrDefault(n, 0) + 1);
}
for (int n : nums) {
if (map.get(n) == 1) {
return n;
}
}
return -1;
}
}
解法二:位运算
如果一个数字出现3次,它的二进制每一位也出现的3次。
如果把所有的出现三次的数字的二进制表示的每一位都分别加起来,那么每一位都能被3整除。
我们把数组中所有的数字的二进制表示的每一位都加起来。
如果某一位能被3整除,那么这一位对只出现一次的那个数的这一肯定为0。
如果某一位不能被3整除,那么只出现一次的那个数字的该位置一定为1。
class Solution {
public int singleNumber(int[] nums) {
int[] k = new int[32];
for (int n : nums) {
for (int i = 0; i < 32; ++i) {
//循环每个数时,把数组中所有的数字的二进制表示的每一位都单独加起来
k[i] += n & 1;
n >>= 1;
}
}
int ret = 0;
for (int i = 31; i >= 0; --i) {
ret <<= 1;
if (k[i] % 3 == 1) {
//如果某一位不能被3整除,那么 ret 的该位一定为 1
ret |= 1;//或(有 1 则 1) 给该位置 1
}
//如果能被3整除,那么这一位对 ret 肯定为0
}
return ret;
}
}