首先考虑一个简单问题:一个数组里除了一个数字之外,其他的数字都出现了两次,找出这个只出现一次的数字。 根据数字出现的次数,我们想到了异或运算的性质:任何一个数字异或它自己都等于0 。我们从头到尾依次异或数组中的每一个数字,因为那些出现两次的数字全部在异或中抵消掉了,那么最终的结果刚好是那个只出现一次的数字。 代码如下:
/**一个数组里除了一个数字之外,其他的数字都出现了两次,找出这个只出现一次的数字*/ public int FindNumAppearOnce(int[] array){ if (array == null || array.length == 0) return; int len = array.length, res = 0; for(int i = 0; i < len; i++){ res = res ^ array[i]; } return res; }然后考虑这个问题的变种版本:一个整型数组里除了两个数字之外,其他数字都出现了两次。 找出这两个只出现一次的数字。 根据上面思路:如果将所有所有数字相异或,则最后的结果肯定是那两个只出现一次的数字异或的结果。 所以根据异或的结果1所在的位,把数字分成两个子数组,分组标准是数字在这个位上的值是否为1;每一半里含有只出现一次的数据和成对出现的数据,这样继续对每一半相异或则可以分别求出两个只出现一次的数字。 代码如下:
/**一个数组里除了二个数字之外,其他的数字都出现了两次,找出这个只出现一次的数字*/ public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { if (array == null || array.length < 2) return; int temp = 0; for (int i = 0; i < array.length; i++) temp ^= array[i]; int indexOf1 = findFirstBitIs(temp); for (int i = 0; i < array.length; i++) { if (isBit(array[i], indexOf1)) num1[0] ^= array[i]; else num2[0] ^= array[i]; } } /**找到异或结果中第一个为1的位数*/ public int findFirstBitIs(int num) { int indexBit = 0; while (((num & 1) == 0) && (indexBit) < 8 * 4) { num = num >> 1; ++indexBit; } return indexBit; } /**判断其他数字在第一个为1的位数上是否为1*/ public boolean isBit(int num, int indexBit) { num = num >> indexBit; return (num & 1) == 1; }最后考虑这个问题的复杂版本:一个数组里除了一个数字之外,其他的数字都出现了三次,找出这个只出现一次的数字。 思路:把所有出现三次数字的二进制表示的每一位相加,如果某一位的和能被3整除,说明那个只出现一次的数在这一位为0,如果某一位的和不能被3整除,说明那个只出现一次的数在这一位为1,由此找出这个只出现一次的数字。 代码如下:
/**一个数组里除了一个数字之外,其他的数字都出现了三次,找出这个只出现一次的数字*/ public int singleNumber(int[] A) { int res=0; for(int i=0;i<32;i++){ int bit=0; for(int j=0;j<A.length;j++){ bit+=(A[j]>>i)&1; } res|=(bit%3)<<i; } return res; }此外,如果此题不要求空间限制的话,可以使用位图法BitMap。
/**1.用hashset属性:值不重复*/ public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashSet<Integer> set = new HashSet<>(); for (int i = 0;i < array.length;i++){ if(!set.add(array[i])){ set.remove(array[i]); }else{ set.add(array[i]); } Object[] temp =set.toArray(); num1[0] = (int) temp[0]; num2[0] = (int) temp[1]; } /** 2.与上面类似*/ public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { ArrayList<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < array.length; i++) { if (!arrayList.contains(array[i])) { arrayList.add(array[i]); } else { arrayList.remove(new Integer(array[i])); } if (arrayList.size() > 1) { num1[0] = arrayList.get(0); num2[0] = arrayList.get(1); } } }