import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashMap<Integer,Integer> map = new HashMap<>(); for(int i = 0; i < array.length; i++){ if(!map.containsKey(array[i])){ map.put(array[i] , i); }else{ map.remove(array[i]); } } Object[] a = map.keySet().toArray(); num1[0] = (int) a[0]; num2[0] = (int) a[1]; } }
import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { if (array == null) { return; } HashSet<Integer> set = new HashSet<>(); for (Integer num : array) { if (set.contains(num)){ set.remove(num); }else { set.add(num); } } int i = 0; for (Integer a: set) { if (i == 0){ num1[0] = a; }else { num2[0] = a; } i++; } } }
import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashMap<Integer,Integer> map=new HashMap<>(); for(int i: array){ if(!map.containsKey(i)){ map.put(i,1); }else{ map.put(i, map.get(i)+1); } } int[] ans=new int[2]; int cnt=0; for(int i:array){ if(map.get(i)==1){ ans[cnt]=i; cnt++; } } num1[0]=ans[0]; num2[0]=ans[1]; } }
位异或 import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int eor=0; for(int i=0;i<array.length;i++){ eor=eor^array[i]; } int rightOne=eor&(~eor+1); for(int i=0;i<array.length;i++){ if((array[i]&rightOne)!=0){ num1[0]=num1[0]^ array[i]; //num1[0]初始为0 } } num2[0]=eor^num1[0]; } }
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { Arrays.sort(array); for(int i=0;i<array.length;i++){ if(i+1<array.length && array[i]==array[i+1]){ i++; }else if(num1[0]==0){ num1[0]=array[i]; }else{ num2[0]=array[i]; } } }
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int xor1 = 0; for (int i = 0; i < array.length; i++) { xor1 = xor1 ^ array[i]; } // 在xor1中找到第一个不同的位对数据进行分类,分类为两个队列对数据进行异或求和找到我们想要的结果 int index = 1; while ((index & xor1) == 0) index = index << 1;// 左移 int result1 = 0; int result2 = 0; // 根据index的位数进行分组 for (int i = 0; i < array.length; i++) { if ((index & array[i]) == 0) result1 = result1 ^ array[i]; else result2 = result2 ^ array[i]; } num1[0] = result1; num2[0] = result2; } }
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { if(array == null || array.length == 0) return; // 先异或一次取得结果为两个不同数得异或结果,两个相同数异或等于0了 int length = array.length; int first = 0; for(int i = 0 ; i < length ; i++){ first ^= array[i]; } // 取first中最低位的1,可以使用lowbit // 这种操作会返回最后一个1及其后面所有零,如lowbit(0011 1000) = 0000 1000 int lowbit = first & -first; // 根据lowbit分组即可,分组时直接加入异或 int a = 0; int b = 0; for(int i = 0 ; i < length ; i++){ if((array[i] & lowbit) == 0){ a ^= array[i]; }else{ b ^= array[i]; } } // 最终因为相同的数被分到了同一数组,同的两个数被分到了不同数组 // 因此最终a和b数值即为所求结果 num1[0] = a; num2[0] = b; return; } }
public class Solution { /** 题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 题解: 因为题目提示了用位运算: 位运算中异或的性质:两个相同数字异或=0,一个数和0异或还是它本身。 1. 将array 的全部元素进行 异或, 如果结果temp为 0 ,表示不存在两个不同的数字,直接退出;否则进入下一步 2. 找出 temp 的最右边的 1 所在的位置,因为异或操作“相同为0,不同为1”,如果该位置index 为 1 表示,不同的两个数字再该位置上不同; 3. 根据 index 把 array 分成两个子数字, 其中任一个子数组有且仅有一个单一的数字,所以直接与 num1[0]/ num2[0] 进行异或, 最终的异或结果是该单一的数字(以为成对的元素已经异或为0) */ public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int temp = 0; for (int i = 0; i < array.length; i++) { temp ^= array[i]; } // 存储 temp 的最右边的 1 所在的位置 int index = 0; while ((temp & 1) == 0) { index++; // >> 带进位右移 temp = temp >> 1; } // 根据 index 可以把 array 分为两个部分,每个部分均有一个单一的数字 num1[0] = num2[0] = 0; for (int i = 0; i < array.length; i++) { // array[i] >> index) & 1 : 求 array[i] 数字的第 index 位的数字是1 还是 0, 以此为array 的分割条件 if (((array[i] >> index) & 1) == 1) { num1[0] ^= array[i]; }else { num2[0] ^= array[i]; } } } }
import java.util.HashSet; import java.util.Iterator; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashSet<Integer> result = new HashSet<>(); for(int i = 0; i < array.length; i++){ if(result.contains(array[i])){ result.remove(array[i]); continue; } result.add(array[i]); } Iterator<Integer> iterator = result.iterator(); while(iterator.hasNext()){ num1[0] = iterator.next(); num2[0] = iterator.next(); } } }
import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { // 一个数第一次遇到存入 set,第二次遇到将该数从 set 中删除,最后剩下的两个就是只出现一次的 TreeSet<Integer> set = new TreeSet<>(); for(Integer x : array) { if(!set.contains(x)) { set.add(x); } else { set.remove(x); } } num1[0] = set.pollFirst(); num2[0] = set.pollFirst(); } }
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int[] arr = new int[128]; for (int i=0;i<array.length;i++) { if (arr[array[i]]==0) { arr[array[i]] = 1; } else { arr[array[i]] = 2; } } boolean flag = false; for (int i=0;i<arr.length;i++) { if (arr[i]==1) { if (!flag) { num1[0] = i; flag = true; } else { num2[0] = i; break; } } } } }
import java.util.HashMap; import java.util.Set; //num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashMap<Integer, Integer> hashMap = new HashMap<>(); for (int i = 0; i < array.length; i++) { if (!hashMap.containsKey(array[i])){ hashMap.put(array[i],1); }else { hashMap.put(array[i],(hashMap.get(array[i]))+1); } } int count = 0; Set<Integer> keySet = hashMap.keySet(); for (int key : keySet) { if (hashMap.get(key) == 1) { if (count == 0) { num1[0] = key; count++; } else if (count == 1){ num2[0] = key; } else { break; } } } } }
/*思路:先排序,那么相同的两个数必定是挨着的; 判断第一个数,若和第二个不相等,第一个肯定没有重复的; 判断最后一个数,若和倒数第二个不相等,最后一个肯定没有重复的; 再循环判断第二个数到倒数第二个数,若每个数和前后两个数都不同,那么是没有重复的; */ import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { Arrays.sort(array);//排序,从小到大 int[] temp=new int[2];//用于存放num1[0],num2[0]两个不重复的数 int k=0; //判断第一个数是否有重复 if(array[0]!=array[1]){ temp[k]=array[0]; k++; } //判断最后一个数是否有重复 if(array[array.length-1]!=array[array.length-2]){ temp[k]=array[array.length-1]; k++; } //判断第二个到倒数第二个数是否有重复 for(int i=1;i<array.length-1;i++){ if ((array[i]!=array[i-1])&&(array[i]!=array[i+1])) { temp[k]=array[i]; k++; } } num1[0]=temp[0]; num2[0]=temp[1]; System.out.println(num1[0]+" "+num2[0]); } }
public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashSet<Integer> s = new HashSet<>(); for(int var:array){ if(s.contains(var)) s.remove(var); else s.add(var); } Iterator it = s.iterator(); num1[0] = (int)it.next(); num2[0] = (int)it.next(); } }
思路二、利用异或运算很厉害!!!!具体操作流程:
因为如果a==b a^b = 0 0^c = c
异或是同0异1!!!
因此其余数据都是重复的,我们从头到尾异或,最后的结果就是这两个不同的数据的异或结果。
然后我们再找出异或结果中的1(代表两个数据在这个位上不同,也就是一个是1一个是0)那么接着我们再按照这个将数据分为两组,一组是在该位是1一组是在该位是0,那么在进行一次全体异或,就可以得出两个数据了!!!!!!!!!!
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int result=0; for(int var:array) result^=var; int flag = 1; //从右往左找到第一个1,也就是两个位数不同的位 while((result&flag)==0) flag<<=1; for(int var:array) { if((var&flag)==0) num1[0]^=var; else num2[0]^=var; } }
import java.util.*; //num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { /** * * 对于题目中说除了两个单个数字外,其他的都出现偶数次。我们需要从这句话入手,寻求更优的解决思路。 * * 我们知道,位运算中异或的性质是:两个相同数字异或=0,不相同的话肯定不为0,一个数和0异或还是它本身。 * * 这个题目的突破口在哪里?题目为什么要强调有一个数字出现一次,其他的出现两次?我们想到了异或运算的性质: * 任何一个数字异或它自己都等于0 。也就是说,如果我们从头到尾依次异或数组中的每一个数字, * 那么最终的结果刚好是那个只出现一次的数字,因为那些出现两次的数字全部在异或中抵消掉了(异或运算的交换律,可以参考博客: * https://blog.csdn.net/luzhensmart/article/details/107586619)。 * * 有了上面简单问题的解决方案之后,我们回到原始的问题。如果能够把原数组分为两个子数组。 * 在每个子数组中,包含一个只出现一次的数字,而其它数字都出现两次。如果能够这样拆分原数组, * 按照前面的办法就是分别求出这两个只出现一次的数字了。 * * 我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。 * 因为其它数字都出现了两次,在异或中全部抵消掉了。由于这两个数字肯定不一样,那么这个异或结果肯定不为0 , * 也就是说在这个结果数字的二进制表示中至少就有一位为1 。 * * 我们在结果数字中找到第一个为1 的位的位置,记为第N 位。现在我们以第N 位是不是1 为标准把原数组中的数字分成两个子数组, * 第一个子数组中每个数字的第N 位都为1 ,而第二个子数组的每个数字的第N 位都为0 。 * * 现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其它数字都出现了两次。 * 因此到此为止,所有的问题我们都已经解决。 */ public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { if(array == null ||array.length <= 1){ num1[0] = 0; num2[0] = 0; return; } //异或运算结果 int xorResult = 0; for(int i=0;i<array.length;i++){ xorResult ^= array[i]; } /** * int 4字节 32bit 最高位为正负数代表 计算二进制结果xorResult从左到右的顺序 第一个位置为1的位置 * 从左开始找到这个异或结果第一个为1的索引 */ int index = 0; while((xorResult&1)==0 && index < 32){ xorResult = xorResult >> 1; index++; } //以这个索引处是否为1作为判定标准,就将两个不同的数分离开了 //下面就是分两批不停地疑惑,就会得到这两个不同的数 for(int j=0;j<array.length;j++){ //这样就可以分别找到index处为1的独特解以及为0的独特解 if(targetIndexIs1(array[j],index)){ num1[0] ^= array[j]; }else{ num2[0] ^= array[j]; } } } /** * 判断num的index(从左往右看)是否为1 */ public boolean targetIndexIs1(int target,int index){ target = target >> index; if((target&1) == 1){ return true; }else{ return false; } } }
import java.util.HashMap; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { if( array == null || array.length <=1) return; HashMap<Integer, Integer> map = new HashMap<>(); for(int i=0; i< array.length ; i++){ if(map.containsKey(array[i])){ map.put(array[i], 1); }else{ map.put(array[i], null); } } boolean flag = true; for(Integer key : map.keySet()){ if(map.get(key) == null){ if(flag){ num1[0]= key; flag = false; }else{ num2[0]= key; } } } } }
/num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int ret = 0; for (int i : array) { ret ^= i; } //取出某一位上不同 num1[0] = 0; num2[0] = 0; ret &= (-ret); for (int i : array) { if ((ret & i) == 0) { num1[0] ^= i; } else { num2[0] ^= i; } } } }
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 import java.util.Arrays; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { Arrays.sort(array);//先对数组排序 if(array[0]!=array[1]) {//对第一个数单独判断 num1[0] = array[0]; for (int i = 1; i < array.length-1; i++) { //因为要判断当前索引是否和前后数字相等,所以 i < array.length-1 if(array[i]!=array[i-1] && array[i]!=array[i+1]) { num2[0] = array[i]; } } }else {//else后表示第一个数是重复的,继续寻找 int index = 0; for (int i = 1; i < array.length-1; i++) { if(array[i]!=array[i-1] && array[i]!=array[i+1]) { num1[0] = array[i]; index = i;//记录第一次的找到的索引,然后break break; } } for (int i = index+1; i < array.length-1; i++) { if(array[i]!=array[i-1] && array[i]!=array[i+1]) { num2[0] = array[i]; } } //循环条件 i < array.length-1,因此不会遍历到最后一个数 //如果循环完没有找到第2个数,那么最后一个数就是第二个数,单独判断一下。 if(array[array.length-2]!=array[array.length-1]) num2[0] = array[array.length-1]; } } }
//暴力解法:直接将数字排序,相同的两个数必然相邻,遍历时跨度为2,遇到相邻两数不一致时,取出该数,跨度为1继续遍历 import java.util.*; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { Arrays.sort(array); int j = 0; int[] arr = new int[2]; for(int i=0;i<array.length-1;i+=2){ if(array[i]!=array[i+1]){ arr[j++]=array[i]; i--; if(j==2) break; } } //如果第二个数在最后面,则上述的遍历将会跳过这个数 if(array[array.length-1]!=array[array.length-2]){ arr[1]=array[array.length-1]; } num1[0] = arr[0]; num2[0] = arr[1]; } }
class Solution { public: void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) { if(data.size()<2) return ; int size=data.size(); int temp=data[0]; for(int i=1;i<size;i++) temp=temp^data[i]; if(temp==0) return ; int index=0; while((temp&1)==0){ temp=temp>>1; ++index; } *num1=*num2=0; for(int i=0;i<size;i++) { if(IsBit(data[i],index)) *num1^=data[i]; else *num2^=data[i]; } } bool IsBit(int num,int index) { num=num>>index; return (num&1); } };
可以用位运算实现,如果将所有所有数字相异或,则最后的结果肯定是那两个只出现一次的数字异或的结果,所以根据异或的结果1所在的最低位,把数字分成两半,每一半里都还有只出现一次的数据和成对出现的数据
这样继续对每一半相异或则可以分别求出两个只出现一次的数字