LeetCode—260. Single Number III
题目
https://leetcode.com/problems/single-number-iii/description/
给出一个数组,里面的元素有两个只出现1次,其他的元素出现2次。要求找出只出现1次的元素返回。
思路及思路
这道题可以类比136.Single Number。有的方法是可以通用的。
第一种方法:
使用hashmap,若果出现两次就从hashmap中删除相应元素,最后输出hashmap中的元素就可以了。具体可以参看代码。但是这种方法效率比较低,只能击败17%左右
第二种方法:
依然采用异或操作的方法,回想136的思路,将所有的元素异或,出现两次的元素全部消去,只有出现过一次的元素胡留下来。回到这道题,有两个元素出现2次,若果像136直接进行异或,肯定不能得到最终结果。那么怎么办呢/
我们可以将数组分成两部分,让出现过一次的两个数字a,b分别出现在两部分中,这样我们分别在这两部分数组里面进行136的方法就可以了。然后就引出了另一个问题:怎么将这两个数分到两部分里呢
因为两个不同数进行异或,结果至少有一位是1,然后我们通过一定方法(正数和它负值按位与的结果是原始最右边非0位的数字为1)将这个结果转化为原始数最右端非零位是1的数,记为flag,用flag去和原数组每一个数做与操作,这样所有的结果要么是1,要么是0,并且a,b会被分到两个部分里,接下来用136的方法就可以了。
代码
class Solution {
public int[] singleNumber(int[] nums) {
int len = nums.length;
int[] result = {0, 0};
HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
for(int i=0; i<nums.length; i++){
if(hm.containsKey(nums[i])){
hm.remove(nums[i]);
}else{
hm.put(nums[i], i);
}
}
int i=0;
for(Map.Entry<Integer, Integer> m : hm.entrySet()){
result[i] = m.getKey();
i++;
}
return result;
}
}
class Solution {
public int[] singleNumber(int[] nums) {
int[] result = new int[2];
int len = nums.length;
int aXORb = 0;
for(int num:nums){
aXORb ^= num;
}
aXORb &= -aXORb;//正数和它负值按位与的结果是原始最右边非0位的数字为1
for(int num:nums){
if((num&aXORb) == 0){
result[0] ^= num;
}else{
result[1] ^= num;
}
}
return result;
}
}