题目
输入一个整数数组,数组中只有一个数字出现了一次,而其他数字都出现了3次。请找出那个只出现一次的数字。例如,如果输入的数组为[0,1,0,1,0,1,100],则只出现一次的数字是100。
思路
1.将数组转换成Map结构,数字作为key,出现的次数为value,遍历map集合,返回value=1的key,这种做法很简单,但是效率也比较低。
2.一个整数是由32个0或1组成的。我们可以将数组中所有数字的同一位置的数位相加。如果将出现3次的数字单独拿出来,那么这些出现了3次的数字的任意第i个数位之和都能被3整除。因此,如果数组中所有数字的第i个数位相加之和能被3整除,那么只出现一次的数字的第i个数位一定是0;如果数组中所有数字的第i个数位相加之和被3除余1,那么只出现一次的数字的第i个数位一定是1。这样只出现一次的任意第i个数位可以由数组中所有数字的第i个数位之和推算出来。当我们知道一个整数任意一位是0还是1之后,就可以知道它的数值。
代码
解法1,暴力
public int singleNumber(int[] nums) {
Map<Integer,Integer> map = new HashMap();
for (int i = 0; i < nums.length; i++) {
if(!map.containsKey(nums[i])){
map.put(nums[i],1);
}else {
int a = map.get(nums[i]) + 1;
map.put(nums[i],a);
}
}
int x = 0;
for (Map.Entry<Integer, Integer> i : map.entrySet()) {
if (i.getValue() == 1) {
x = i.getKey();
break;
}
}
return x;
}
解法2,运用位运算
public int singleNumber(int[] nums) {
int[] bitNums = new int[32];
for(int num : nums){
for (int i = 0; i < 32; i++) {
bitNums[31 - i] += num >> (31 - i) & 1;
}
}
int result = 0;
for (int i = 0; i < 32; i++) {
result += (bitNums[31 - i]%3) << (31 - i);
}
return result;
}
说明:
- “ bitNums[31 - i] += num >> (31 - i) & 1”,判断每个数二进制数位是0或1,统计对应数位1的个数。