前言:
看到了一个比较新颖的解决办法,值得学习。
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
解题思路
这道题首先我自己想到的办法,就是对数字进行统计,然后在查找。这里我是用的是HashMap来做保存统计。这种方法这个实现,但是需要两次循环。所以就去借鉴了别人的想法。下面说一下这个比较好的方法。
异或有一个性质,任何一个数字异或他自己都等于0。那么我们从头到尾一次异或数组中的每个数字,那么最终的结果刚好是那个只出现一次的数字,因为那些成对出现两次的数字全部都在异或中抵消了。
根据这个性质,我们尝试着把这个原数组分成两个子数组,使得每个子数组包含一个只出现一次的数字,而其他数字都成对出现两次。如果能够这样拆分成两个数组,那么我们就可以按照从头到尾依次异或数组中的每个数字,那么最终的结果刚好是那个只出现一次的数字,因为哪些成对出现两次的数字全部都在异或中抵消了。这里我们两个子数组该怎么分呢?我们还是从头到尾依次异或数组中的每个数字,那么最终得到的结果就是两个只出现一次的数字的异或的结果,因为其他数字都出现了两次,在异或中全部抵消了。由于这两个数字肯定不一样,那么异或的结果肯定不为0,也就说,在这个结果数字的二进制表示中至少有一位为1.我们在结果数字中找到第一个为1的位的位置,记为第n位。现在我们以第n位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第n位都是1,而第二个子数组中每个数字的第n位都是0.由于我们分组的标准是数字中的某一位是1还是0,那么出现了两次的数字肯定被分配到同一个子数组。因为两个相同的数字的任意一位都是相同的,我们不可能把两个相同的数字分配到两个子数组中去,于是我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现了一次的数字,而其他数字都出现了两个。我们已经知道了如何在数组中找出唯一一个只出现一次的数字,因此,到此为止我们的问题就解决了。
说起来确实很长。理解了这个思路就好了。
代码样例
HashMap解法
package com.asong.leetcode.FindNumsAppearOnce;
import java.util.HashMap;
/**
* 数组中只出现一次的数字、
* 题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
*/
public class Solution {
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
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.get(array[i]) == null)
{
map.put(array[i],1);
}else {
map.put(array[i],map.get(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];
}
}
}
}
}
异或解决
package com.asong.leetcode.FindNumsAppearOnce;
/**
* 找出数组中只出现一次的两个数字
*/
public class Solution1 {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int xor1 = 0;
for (int i = 0; i < array.length; i++) {
xor1 = xor1 ^ array[i];
}
int index = 1;
while ((index & xor1)==0)
{
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;
}
public static void main(String[] args) {
int[] array = {2,4,3,6,3,2,5,5};
int[] num1 = new int[1];
int[] num2 = new int[1];
Solution1 solution = new Solution1();
solution.FindNumsAppearOnce(array,num1,num2);
}
}