• 剑指Offer对答如流系列


    面试题39:数组中出现次数超过一半的数字

    题目描述

    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

    问题分析

    大家最容易想到的思路是 数字次数超过一半,则说明排序之后数组中间的数字一定就是所求的数字。

    既然是数组,要牵扯到排序,大家一般都会选用经典快速排序或者随机快速排序。随机快速排序由于每次划分的依据是从数组随机选出的,所以数据状况对它的影响减弱,时间复杂度为 O(N*logN),而快速排序受数据状况的影响,时间复杂度差的话为O(n^2)。本文使用的是快速排序,书写比较方便。

    其实还有一个比较有意思,而且非常好的算法思想,被描述为阵地攻守的思想:

    第一个数字作为第一个士兵,守阵地;count = 1;
    遇到相同元素,count++;
    遇到不相同元素,即为敌人,同归于尽,count--;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。
    再加一次循环,记录这个士兵的个数看是否大于数组一般即可。
    

    也就是数字次数超过一半,则说明:该数字出现的次数比其他数字之和还多

    遍历数组过程中保存两个值:一个是数组中某一数字,另一个是次数。遍历到下一个数字时,若与保存数字相同,则次数加1,反之减1。若次数=0,则保存下一个数字,次数重新设置为1。由于要找的数字出现的次数比其他数字之和还多,那么要找的数字肯定是最后一次把次数设置为1的数字。

    问题解答

    思路一(不推荐)

        // 表示输入是否有效
        boolean isInputInvalid = true;
        // 快速排序
        public int MoreThanHalfNum(int [] array) {
            if(array==null ||array.length <= 0) {
                return 0;
            }
            int low=0;
            int high=array.length-1;
            int index=partition(array, low, high);
    
            while(index != array.length>>1){
                if(index < array.length>>1 ){
                    low = index+1;
                    index = partition(array,low,high);
                } else {
                    high = index-1;
                    index=partition(array,low,high);
                }
            }
    
            //判断次数是否超过一半
            int num=array[index];
            int times=0;
            for(int i=0;i < array.length;i++){
                if(array[i]==num){
                    times++;
                }
            }
            if(times*2 > array.length){
                isInputInvalid=false;
                return num;
            }
            return 0;
        }
    
        private int partition(int[] array,int low ,int high){
    
            int pivotKey=array[low];
            while(low < high){
                while(low < high &&  array[high] >= pivotKey) {
                    high--;
                }
                int temp=array[low];
                array[low]=array[high];
                array[high]=temp;
                while(low < high && array[low] <= pivotKey) {
                    low++;
                }
                temp=array[low];
                array[low]=array[high];
                array[high]=temp;
            }
            return low;
        }
    

    思路二(推荐)

    	// 表示输入是否有效
        boolean isInputInvalid = true;
    
        public int MoreThanHalfNum(int [] array) {
            if(array==null || array.length <= 0) {
                return 0;
            }
    
            int num=array[0];
            int count = 1;
            for(int i=1;i<array.length;i++){
                if(count == 0) {
                    num=array[i];
                    count++;
                }
                else if(array[i] == num) {
                    count++;
                }
                else {
                    count--;
                }
            }
            
            if(count > 0){
                int times=0;
                for(int i=0;i<array.length;i++){
                    if(array[i] == num){
                        times++;
                    }
                }
                if(times*2 > array.length){
                    isInputInvalid=false;
                    return num;
                }
            }
            return 0;
        }
    
  • 相关阅读:
    MySql查询分页数据
    出现不不能引java.util.Date包的情况
    类的反射实例(servlet的抽取)
    关于C++ const 的全面总结
    教你用笔记本破解无线路由器password
    使用 HTML5 webSocket API实现即时通讯的功能
    用户研究经验分享
    我的学习笔记_Windows_HOOK编程 2009-12-03 11:19
    用户參与记录存储的演变
    IC芯片
  • 原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246441.html
Copyright © 2020-2023  润新知