一个只出现一次的数,其他出现两次
- 全部的数异或,最后的数就是要找的数
class Solution {
public int singleNumber(int[] nums) {
int res = nums[0];
for(int i=1;i<nums.length; i++){
res ^= nums[i];
}
return res;
}
}
两个只出现一次的数,其他出现两次
-
假设两个出现一次的数为p,q,如果能找到p和q中间的数,将数组分为两半,左边异或得到p,右边异或得到q。
-
怎么找到 p 和 q 中间的数字 r 呢?二分。
-
但是,你以为这完了吗?异或和为 00 其实并不代表 要找的元素不在这里面,因为有可能 00 只出现了 11 次! 所以这种思路需要特判一下某个数为 00 的情况。
class Solution {
public int[] singleNumbers(int[] nums) {
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
int zero = 0;
int sum = 0;
for(int i=0; i<nums.length; i++) {
min = Math.min(min, nums[i]);
max = Math.max(max, nums[i]);
if(nums[i] == 0)
zero += 1;
sum ^= nums[i];
}
if(zero == 1)
return new int[] {sum, 0};
int left = min, right = max;
while(left <= right) {
//int mid = (left < 0 && right > 0)? (left + right) >> 1: left + (right - left) / 2;
int mid = (left + right) / 2;
int leftSum = 0, rightSum = 0;
for(int n : nums) {
if(n < mid)
leftSum ^= n;
else
rightSum ^= n;
}
if(leftSum != 0 && rightSum != 0)
return new int[] {leftSum, rightSum};
if(leftSum == 0)
left = mid +1;
if(rightSum == 0)
right = mid - 1;
}
return null;
}
}
只出现一次的数,其他数字出现三次
class Solution {
public int singleNumber(int[] nums) {
//二进制中各个位上1的个数
int[] numOne = new int[32];
for(int n:nums){
for(int i=0;i<32;i++){
numOne[i] += n&1;
n >>= 1;
}
}
//%3
int res = 0;
for(int i=0;i<32;i++){
res <<= 1;
res |= numOne[31 - i] % 3;
}
return res;
}
}