zoukankan      html  css  js  c++  java
  • 剑指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;
        }
    
  • 相关阅读:
    干货分享:QQ群排名霸屏优化规则靠前的新技术
    QQ群排名优化到霸屏的策略怎么做?
    百度知道芝麻将,申请资格&权限介绍&奖惩制度(简剖)
    新媒体运营之如此微信养号不易封
    知道引流于需求之上 势必更为精准有效
    价值内容争夺背后的流量推荐 以及利润分发逻辑
    深度剖析:自媒体爆文十大标题写法
    据统计:90%的爆文都这样敲出来滴
    短视频不为人知的素材来源 以及平台推荐的黑盒机制
    说什么月入几万 我是不是应该一头撞死?
  • 原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246898.html
Copyright © 2011-2022 走看看