[leetCode]剑指 Offer 56 - II. 数组中数字出现的次数 I、II
解法
有两个数字只出现一次,其余数字出现两次,那么出现两次的数字异或之后为0相互抵消,剩下两个出现一次的数字由于一定不相同,所以异或之后肯定有一位为1。所以可以通过该位是否为1将数组划分为两个子数组,每个数字都只有一个数字出现一次,这样就能通过异或分别找到每个数组中只出现一次的数字了。
class Solution {
public int[] singleNumbers(int[] nums) {
if (nums == null) return null;
if (nums.length < 2) return new int[]{nums[0],0};
int resultExclusiveOR = 0;
for (int i = 0; i < nums.length; i ++)
resultExclusiveOR ^= nums[i];
int indexOf1 = findFirstBitIs1(resultExclusiveOR);
int[] ans = new int[2];
for (int i = 0; i < nums.length; i++) {
if (isBit1(nums[i], indexOf1)) {
ans[0] ^= nums[i];
} else {
ans[1] ^= nums[i];
}
}
return ans;
}
private int findFirstBitIs1(int num) {
int indexBit = 0;
while (((num & 1) == 0) && (indexBit < 32)) {
num = num >> 1;
++indexBit;
}
return indexBit;
}
private boolean isBit1(int num, int index) {
num = num >> index;
return ((num & 1) == 1);
}
}
解法
由于除了只出现一次的数字之外其余数字都出现三次,那么把出现三次的数字每一位加起来肯定能被3整除。所以我们可以把数组中所有的数字每一位都加起来,如果某一位能被3整除则说明只出现一次的数字在该位为0,否则为1。
class Solution {
public int singleNumber(int[] nums) {
if (nums == null || nums.length == 0) return 0;
// 长度为32的辅助数组,用于记录数字每一位的和
int[] bitSum = new int[32];
for (int i = 0; i < nums.length; i++) {
int bitMask = 1;
for (int j = 31; j >= 0; j--) {
int bit = nums[i] & bitMask;
if (bit != 0) {
++bitSum[j];
}
bitMask = bitMask << 1;
}
}
int result = 0;
for (int i = 0; i < 32; i++) {
result = result << 1;
result += bitSum[i] % 3;
}
return result;
}
}