zoukankan      html  css  js  c++  java
  • Easy | LeetCode 169 | 剑指 Offer 39. 数组中出现次数超过一半的数字

    剑指 Offer 39. 数组中出现次数超过一半的数字

    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

    你可以假设数组是非空的,并且给定的数组总是存在多数元素。

    示例 1:

    输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
    输出: 2
    

    方法一:Hash计数

    先遍历一遍数组, 将每个数字出现的次数存到HashMap当中, 然后再遍历HashMap, 找是否有超过一半的数字, 如果有, 立即返回true。否则返回false;

    方法二:多数投票算法(Boyer-Moore Algorithm)

    基本算法:两趟扫描, 第一趟扫描, 找到可能成为这个超过一半数字的候选, 第二趟扫描, 看这个候选出现的次数是否超过一半。

    找候选的过程如下:

    维持一个计数器, 初始值为0。

    当计数器为0时, 设置当前值为候选值。并且将计数器自增一次。

    当计数器不为0时, 如果当前值与候选值相同, 则计数器自增, 如果不相同, 则计数器自减。

    当遍历结束时, 如果计数器大于0, 则可能存在一个超过一半的数字。如果真的有, 那就是候选值。

    public int majorityElement(int[] nums) {
        int candidate = nums[0];
        int count = 1;
        for(int i = 1; i < nums.length; i++) {
            if (count == 0) {
                candidate = nums[i];
                count = 1;
            } else if (nums[i] == candidate){
                count += 1;
            } else {
                count -= 1;
            }
        }
        return candidate;
    }
    

    为什么这种策略能够成功?

    (1) 我们先分析数组中只有1,0的情况, 我们看这两个数字, 谁比谁多, 多的那个一定是多数元素(超过一半数量)。比如[1,1,0,0,0,1,0]。对于只有1,0的情况, 最简单的想法是我直接设两个计数器统计个数进行比较。一个更好的想法是:我设置一个计数器, 当遇到1时, 自增, 当遇到0时, 自减。这样我遍历完成时, 如果计数器大于0, 则说明1多, 自减意味着0的个数和1的个数相互抵消了, 计数器的最终值就是1比0多出来的个数。

    (2) 上面0,1的应该是非常好理解的, 我现在在0,1数字引入其他数字来分析。比如[1,1,0,1,2,0,3]。在这种情况下, 候选值和计数器值如下:

    1 1 0 1 2 2 3
    index 0 1 2 3 4 5 6
    candidate 1 1 1 1 1 1 0
    count 1 2 1 2 1 0 1

    当下标为[0,5]时, 候选值是1, count值代表为1比其他数字多出来的数字, 这个是比较容易理解的。当count变为0时, 代表当前候选值1被其他数字抵消完了, 1不可能成为多数元素。这个也是比较好理解的。有人可能要问了, 为什么就把count为0的哪个值(这里是3), 作为候选值, 在下标[0,5]中间, 不还是有其他数吗?他们为什么不能作为候选值呢?比如例子里有2个2, 他们为什么不能当做候选值?

    其实思路很简单,候选值1在下标[0,5]区间内, 计数器有1开始, 最后变为0, 这个区间内的所有数字, 都是不可能成为多数元素的(至少遍历到下标5时, 这么看是没有问题的, 至于后面某个数字会不会一直增加超过一半, 对当前的判断无关紧要)。因为,当count = 0时, 1的数字, 目前是出现了一半, 而对于不是1的其他数字, 他们的出现的次数, 一定小于或等于当前1的次数, 所以, 这中间出现的元素一定不是多数元素。要理解, 这种策略, 本身是一种“减法策略”。每次count = 0时, 他就把不可能成为多数元素的值给“减掉”, 最后会留下一个值, 它可能成为多数元素。

  • 相关阅读:
    hive order、sort、distribute、cluster by区别与联系
    hive over窗口函数的使用
    hive中row_number() rank() dense_rank()的用法
    hive中文乱码问题
    hive分桶表的学习
    hive的调优经验
    Hive的学习
    hive grouping sets和GROUPING__ID的用法
    hive修复分区或修复表 以及msck命令的使用
    Vue中使用websocket
  • 原文地址:https://www.cnblogs.com/chenrj97/p/14285293.html
Copyright © 2011-2022 走看看