本文共 3340 字,大约阅读时间需要 11 分钟。
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
看到题目的时候确实 有点轻敌了:
乍一看题目,哟吼,这不是就简单的数组计数器就可以搞定了吗?
然后一顿哐哐操作写好算法与测试类:
@Testpublic void ttest1() { int arr[] = { 1, 1, 2, 2, 3, 4, 4, 5}; System.out.println(Arrays.toString(FindNumsAppearOnce_MyTest(arr)));}//num1,num2分别为长度为1的数组。传出参数//将num1[0],num2[0]设置为返回结果public int[] FindNumsAppearOnce_MyTest(int[] array) { int[] ints = new int[array.length]; int[] result = new int[2]; int count = 0; for (int anArray : array) { ints[anArray]++; } for (int i = 0; i <array.length; i++) { if (ints[i]==1){ result[count++]= i; } } return result;}/*输出结果:[3, 5]稳了,没毛病。*/
结果将算法稍作改写丢到牛客网上:
//num1,num2分别为长度为1的数组。传出参数//将num1[0],num2[0]设置为返回结果public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int[] ints = new int[array.length]; int count = 0; for (int i = 0; i < array.length; i++) { ints[array[i]]++; } for (int i = 0; i <array.length; i++) { if (ints[i]==1){ count++; if (count == 1) { num1[0] = i; } else { num2[0] = i; } } } }}
顿时报错:
大意了啊😓 实在妹又想到还有这么大的数字,这对int[]
数组来说确实是不可行的。也就是说用数组计数器的方法不够全面。
不能用数组计数器做那得咋整啊?
仔细审题,题目中说寻找只出现一次的数字
众所周知,Map中的key是不能重复的,如果重复是会自动覆盖前者,因此我们可以利用HashMap进行操作(见解答一)
本题知识点:
不过遍历多次总感觉可以继续优化,查阅资料:
对于查找只出现一次的问题可以用 ^ 异或
运算进行解决
异或的性质:对于整数a,有(1)a^a=0(2)a^0=a(3)a^b^c=a^(b^c)=(a^c)^b
因此首先将数组异或运算一次后会出现一个结果:
根据上述公式(3)是只出现一次的两个数(A^B的结果),这个结果的二进制中的1,表现的是A和B两个数字在二进制上的不同位。
int result = 0;for (int i = 0; i < arr.length; i++) { result ^= arr[i];}System.out.println(result);
接下来就是如何将(A^B)的结果拆分为A和B
//解答一:哈希算法//在Map中用value标识出现的次数,用key存储元素public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); for(int i=0; i < array.length; i++){ if(map.containsKey(array[i])) //如果出现过一次则直接存入{`出现两次的元素`:2} map.put(array[i],2); else map.put(array[i],1); } int count = 0; for(int i=0; i < array.length; i++){ if(map.get(array[i]) == 1){ if(count == 0){ num1[0] = array[i]; count++; }else num2[0] = array[i]; } }}//解答2:运用位移和^运算public String FindNumsAppearOnce_withOperation(int [] array) { int num1[] = new int[1]; int num2[] = new int[1]; int xor1 = 0; for(int i=0; i < array.length; i++){ xor1 = xor1^array[i]; } //在xor1中找到第一个不同的位对数据进行分类,分类为两个队列对数据进行异或求和找到我们想要的结果 int index = 1; while((index & xor1)==0) //因为可能有多个位为1所以需要求一下位置 index = index <<1; int result1 = 0; int result2 = 0; 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; return num1[0]+","+num2[0];}
转载地址:http://oqzg.baihongyu.com/