剑指Offer对答如流系列 - 数组中数字出现的次数

Posted jefferychenxiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer对答如流系列 - 数组中数字出现的次数相关的知识,希望对你有一定的参考价值。

面试题56:数组中数字出现的次数

题目描述

问题(1)数组中只出现一次的两个数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

问题(2)数组中唯一只出现一次的数字

在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

问题分析

问题(1)分析

在这篇文章剑指Offer对答如流系列 - 二进制中 1 的个数中,我们详细探讨了位运算,其中有重要的一条:两个相同的数异或的结果是 0,一个数和 0 异或的结果是它本身

如果数组中只有一个数字只出现一次,我们从头到尾异或每个数字,那么最终的结果刚好是那个只出现一次的数字。

本题里数组中有两个数字只出现一次,所以要做一些处理:

  1. 我们依旧从头到尾异或每个数字,最终的结果就是这两个只出现一次的数字的异或结果,由于两个数不同,结果数字中一定有一位为1,把结果中第一个为1的位置记为第n位。由于是两个只出现一次的数字的异或结果,因此这两个数字在第n位上的数字一定是1和0。

  2. 接下来根据数组中每个数字的第n位上的数字是否为1来进行分组,恰好能将数组分为两个都只有一个数字只出现一次的数组,对两个数组从头到尾异或,就可以得到这两个数了。

问题(2)分析

数字出现了三次,不能直接利用异或位运算进行消除相同个数字。但是仍然可以沿用位运算的思路。

将所有数字的二进制表示的对应位都加起来,如果某一位能被三整除,那么只出现一次的数字在该位为0;反之,为1。

问题解答

问题(1)

  public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {

        if(array==null || array.length<2) {
            return;
        }
        int resultExclusiveOR=0;
        for(int i=0;i<array.length;i++) {
            resultExclusiveOR^=array[i];
        }

        int indexOf1=0;
        while(((resultExclusiveOR&1) == 0) && (indexOf1 <= 32)){
            //易错点:只有n>>1不完整,要n=n>>1
            resultExclusiveOR = resultExclusiveOR>>1;
            indexOf1++;
        }

        num1[0]=0;
        num2[0]=0;
        for(int i=0;i<array.length;i++){
            if(((array[i]>>indexOf1)&1) == 1) {
                num1[0]^=array[i];
            } else {
                num2[0]^=array[i];
            }
        }
    }

问题(2)

    public  int findNumberAppearingOnce(int[] arr) {
        if(arr==null || arr.length<=0) {
            throw new RuntimeException();
        }
        
        int[] bitSum = new int[32];
        Arrays.fill(bitSum, 0);

        for(int i=0;i<arr.length;i++) {
            int bitMask=1;
            for(int j=31; j>=0; j--) {

                int bit= arr[i]&bitMask;
                if(bit!=0) {
                    bitSum[j]+=1;
                }
                bitMask=bitMask<<1;
            }
        }
        int result=0;
        for(int i=0;i<32;i++) {
            result=result<<1;
            result+=(bitSum[i]%3);
        }
        return result;
    }

以上是关于剑指Offer对答如流系列 - 数组中数字出现的次数的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer对答如流系列 - 数组中的逆序对

剑指Offer对答如流系列 - 把数组排成最小的数

剑指Offer对答如流系列 - 连续子数组的最大和

剑指Offer对答如流系列 - 和为s的数字

剑指Offer对答如流系列 - 从1到n整数中1出现的次数

剑指Offer对答如流系列 - 股票的最大利润