[每日一道小算法(四十九)][数组] 数组中只出现一次的数字(剑指offer)

前言:
看到了一个比较新颖的解决办法,值得学习。

题目描述

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

解题思路

这道题首先我自己想到的办法,就是对数字进行统计,然后在查找。这里我是用的是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);
    }
}

发布了157 篇原创文章 · 获赞 34 · 访问量 4364

猜你喜欢

转载自blog.csdn.net/qq_39397165/article/details/104382986