• 剑指28.数组中出现次数超过一半的数字


    题目描述

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

    思路

    思路1:利用排序。对数组排序后,如果符合条件的数存在,则一定是数组中间的那个数。                                      ( 时间复杂度(即排序的复杂度):O(nlogn) )

    思路2:Hash存储次数。遍历一遍,用HashMap存储每个数字出现的次数。                                                              (时间复杂度:O(n),空间复杂度:O(n))

    思路3:摩尔投票法。如果某数字出现的次数超过数组长度的一半,那么它出现的次数比其他所有数字出现次数的和还要多!   (最优解 ~ 时间复杂度:O(n),空间复杂度:O(1))      

    思路3具体过程理解:

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

    解法1(对应思路1)

    import java.util.Arrays;
    public class Solution {
        public int MoreThanHalfNum_Solution(int [] array) {
            if (array == null || array.length <= 0)
                return 0;
            Arrays.sort(array);
            int count = 0;
            for (int x : array){
                if (x == array[array.length >> 1])
                    count++;
            }
            return count > array.length >> 1 ? array[array.length >> 1] : 0;
        }
    }

    解法2(对应思路2)

    import java.util.*;
    public class Solution {
        // 使用HashMap
        public int MoreThanHalfNum_Solution(int [] array) {
            if (array == null || array.length <= 0)
                return 0;
            Map<Integer,Integer> map = new HashMap<>();
            int target = 0; // 存储出现次数最多的数字
            int count = 0;   // 存储出现次数最多数字对应的次数
            for (int x : array){
                map.put(x,map.getOrDefault(x,0) + 1);
                if (map.get(x) > count){
                    count = map.get(x);
                    target = x;
                }
            }
            return count > array.length >> 1 ? target : 0;
        }
    }

    解法3(对应思路3)

    public class Solution {
        // 最优解:摩尔投票法  (遇到相同的+1,不同的-1)
        public int MoreThanHalfNum_Solution(int [] array) {
            if (array == null || array.length <= 0)
                return 0;
            int count = 1, target = array[0];
            for (int i = 1; i < array.length; i++) {
                if (count == 0){
                    target = array[i];
                    count = 1;
                }else{
                    if (target == array[i])
                        count++;
                    else
                        count--;
                }
            }
            // 检验出现频率最高的数字出现的次数是否真的超过数组长度的一半
            // 因为该方法只能保证如果存在超过一半的数就是target,但不代表target一定超过一半
            int sum = 0;
            for (int x : array){
                if (x == target)
                    sum++;
            }
            return sum > array.length >> 1 ? target : 0;
        }
    }

    Note:如果可以保证某个阵营的人数过半,那么最后留下的就一定是这个阵营的士兵。但如果没有任何一个阵营人数过半,那么某个阵营可以猫在最后,在其他阵营都厮杀结束后进入战场,坐收渔翁之利。

    因此,需要加一个检验判断一下 target 是否出现了一半以上。(例如 [ 2,2,2,2,4,5,6,1,7 ], 最后target更新为7)

    参考:

    寻找数组中出现次数超过一半以上的元素
     
  • 相关阅读:
    Win7系统安装Centos7.0双系统(二)
    vue动态加载图片失效
    vuex store更新了数据,但未触发getters
    js获取图片信息
    http请求204
    IOS 伪类:active失效
    js下载blob的形式
    URL的 ? 和 # (hash),如何将参数保存在URL中,用于刷新获取之前的变量?
    vue中修改数组,dom未更新的问题
    vue中使用qrcode,遇到两次渲染的问题
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13510653.html
Copyright © 2020-2023  润新知