zoukankan      html  css  js  c++  java
  • 剑指Offer:面试题29——数组中出现次数超过一半的数字(java实现)

    PS:在前几天的面试中,被问到了这个题。然而当时只能用最低效的方法来解。

    问题描述:

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

    思路1:

    低效的做法:直接用哈稀表来存储<key, value>,并找出出现次数value大于等于一半的那个key。

    代码:

    import java.util.Map;
    import java.util.HashMap;
    public class Solution {
        boolean InvalidInput = false;
        public int MoreThanHalfNum_Solution(int [] array) {
    
            if(array == null || array.length == 0){
                InvalidInput = true;
                return 0;
            }
            Map<Integer, Integer> map = new HashMap<Integer, Integer>();
    
            int max = -1;
            int ind = -1;
            for(int i = 0; i < array.length; i++){
                if(!map.containsKey(array[i])){
                    map.put(array[i], 1);
                }else{
                    map.put(array[i], map.get(array[i])+1);
                }
    
                if(max < map.get(array[i])){
                    max = map.get(array[i]);
                    ind = array[i];
                }
            }
    
            if(max > array.length/2){
                return ind;
            }else{
                return 0;
            }
        }
    }

    思路2:

    —由于出现的次数超过了数组的一半,那么如果我们将数组排序,中间的那个数一定是要求的数字(前提是它一定存在)
    —这里排序时采用快排的基本思想,随机选择一个数,调整数组使得它左边的数都小于它,右边的数都大于它。(参考Partition函数)(下一篇博客的代码中给出了关于Partition函数详细的注释)

    import java.util.Map;
    import java.util.HashMap;
    public class Solution {
        static boolean InvalidInput = false;
        public int MoreThanHalfNum_Solution(int [] array) {
    
            if(array == null || array.length == 0){
                InvalidInput = true;
                return 0;
            }
    
            int middle = array.length >> 1;//设定中位数位置
            int start = 0;
            int end = array.length - 1;
            int index = Partition(array, start, end);//随机选择一个标杆,进行调整数组
    
            while(index != middle){//若所选的标杆最后位置不是中位数的位置,则根据情况对符合情况的部分进行再次调整
                if(index > middle){
                    end = index - 1;
                    index = Partition(array, start, end);
                }else{
                    start = index + 1;
                    index = Partition(array, start, end);
                }
            }
    
            int result = array[middle];
    
            //检查中位数出现的次数是否超过了一半
            if(!CheckMoreThanHalf(array, result)){
                result = 0;
            }
    
            return result;
        }
    
        public static boolean CheckMoreThanHalf(int[] array, int number){
            int times = 0;
            int length = array.length;
    
            for(int i = 0; i < length; i++){
                if(array[i] == number){
                    times++;
                }
            }
    
            boolean isMoreThanHalf = true;
    
            if(times * 2 <= length){
                InvalidInput = true;
                isMoreThanHalf = false;
            }
    
            return isMoreThanHalf;
        }
    
        public static int Partition(int[] array, int start, int end){
            if(array == null || array.length == 0 || start < 0 || end < 0){
                InvalidInput = true;
                return -1;
            }
    
            int index = RandomInRange(start ,end);
            int tmp = array[index];
            array[index] = array[end];
            array[end] = tmp;
    
    
            int small = start - 1;
    
            for(index = start; index < end; index++){
                if(array[index] < array[end]){
                    small++;
    
                    if(small != index){
                        int temp = array[index];
                        array[index] = array[small];
                        array[small] = temp;
                    }
                }
            }
    
    
            small++;
            tmp = array[small];
            array[small] = array[end];
            array[end] = tmp;
    
    
            return small;
    
        }
        public static int RandomInRange(int s, int e){
            int Min = s;
            int Max = e;
            int result = Min + (int)(Math.random() * ((Max - Min) + 1));
            return result;
    
        }
    }

    思路3:

    根据数组特点找出O(n)的算法
    1.数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有的数字出现的次数的和还要多。
    2.因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。
    3.当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1,否则减1.

    代码:

    import java.util.Map;
    import java.util.HashMap;
    public class Solution {
        static boolean InvalidInput = false;
        public int MoreThanHalfNum_Solution(int [] array) {
    
            if(array == null || array.length == 0){
                InvalidInput = true;
                return 0;
            }
    
            int result = array[0];
            int times = 1;
            for(int i = 1; i < array.length; i++){
                if(times == 0){
                    result = array[i];
                }else if(array[i] == result){
                    times++;
                }else{
                    times--;
                }
    
    
            }
    
            if(!CheckMoreThanHalf(array, result)){
                InvalidInput = true;
                result = 0;
            }
            return result;
        }
       public static boolean CheckMoreThanHalf(int[] array, int number){
            int times = 0;
            int length = array.length;
    
            for(int i = 0; i < length; i++){
                if(array[i] == number){
                    times++;
                }
            }
    
            boolean isMoreThanHalf = true;
    
            if(times * 2 <= length){
                InvalidInput = true;
                isMoreThanHalf = false;
            }
    
            return isMoreThanHalf;
        }
    }

    PS:检查出现频率最高的是否超过一半,也还是需要遍历一次数组的。

  • 相关阅读:
    使用openURL实现程序间带参数跳转详解
    [翻译] DFCircleActivityIndicator DF圆形活动状态指示器
    ABC定制视图导航控制器
    [翻译] UIView-draggable 可拖拽的UIView
    [翻译] SFRoundProgressCounterView 带有进度显示的倒计时视图
    [翻译] ColourClock 将时间值转换成背景色
    Solr部署如何启动
    搜索引擎基本工作原理
    面试题 IQ
    解释一下,在你往浏览器中输入一个URL后都发生了什么,要尽可能详细
  • 原文地址:https://www.cnblogs.com/wenbaoli/p/5655704.html
Copyright © 2011-2022 走看看