Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】

题目

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

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

示例 1:

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

限制:

1 <= 数组长度 <= 50000

解题思路

前置知识

摩尔投票算法
摩尔投票算法是一种用于在数组中查找出现次数超过一半的元素的有效算法。算法的核心思想是利用候选元素和计数器进行投票,通过消除不同元素之间的抵消来找到出现次数超过一半的元素。

算法原理
如果数组中存在一个出现次数超过一半的元素,那么这个元素的剩余部分一定会抵消其他元素的出现次数,最终剩下的就是该元素。

算法步骤
初始化候选元素 candidate 为数组的第一个元素,计数器 count 为 1。
从数组的第二个元素开始遍历。
如果当前元素与候选元素相同,则将计数器 count 加 1。
如果当前元素与候选元素不同,则将计数器 count 减 1。
如果计数器 count 减为零,则更新候选元素为当前元素,并将计数器 count 重置为 1。
完成遍历后,候选元素就是出现次数超过一半的元素。
举个例子:

假设数组为 [2, 2, 1, 1, 1, 2, 2]。

初始时,候选元素 candidate 为 2,计数器 count 为 1。
开始遍历数组:
遍历到 2,与候选元素相同,计数器 count 加 1,计数器变为 2。
遍历到 1,与候选元素不同,计数器 count 减 1,计数器变为 1。
遍历到 1,与候选元素不同,计数器 count 减 1,计数器变为 0。
计数器 count 变为 0,更新候选元素为当前元素 1,计数器 count 重置为 1。
遍历到 1,与候选元素相同,计数器 count 加 1,计数器变为 2。
遍历到 2,与候选元素相同,计数器 count 加 1,计数器变为 1。
遍历到 2,与候选元素相同,计数器 count 加 1,计数器变为 0。
计数器count变为0,更新候选元素为当前元素2,计数器count重置为2
完成遍历后,候选元素为 2,它是出现次数超过一半的元素

大概了解了摩尔算法后,我们来看一下这道题

1.题目要求我们查找出出现的次数超过数组长度的一半的数字,我们来画图看一下

2.首先我们先判断一下数组的长度,若数组长度小于2,那么我们直接返回数组中的第一个数字,这个数字就为众数。

3.当数组长度大于2时,我们就使用摩尔投票算法进行查找

举个例子:[1, 2, 3, 2, 2, 2, 5, 4, 2]

我们设置一个变量 cur 去记录当前元素,我们先将nums[0]放入,再设置一个变量 sum用于记录当前元素 cur 的票数,

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第1张图片

 4.然后我们开始遍历数组nums,因为已经将nums[0] 放进了cur中,所以我们从nums[1]开始遍历,i = 1 时,nums[i] = 2,此时sum 不等于0,所以 我们不用重新赋值,我们去判断cur 是否等于 nums[1] ,此时cur != nums[1], 所以我们要将 sum --,

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第2张图片

5.再往后遍历时,我们发现sum等于0,所以我们只需要对cur重新赋值即可,并将sum 变为1Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第3张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第4张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第5张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第6张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第7张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第8张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第9张图片 

6.按照摩尔投票的思路一直遍历到数组的最后一位,保存再 cur 中的数就是我们要求的中位数。 

 

代码实现

class Solution {
    public int majorityElement(int[] nums) {
        //首先我们判断一下数组中的元素是否小于2,若小于2则直接返回
        if(nums.length < 2){
            return nums[0];
        }
        //用于存放当前元素
        int cur = nums[0];
        //用于存放出现次数
        int sum = 1;
        //开始遍历数组
        for(int i = 1; i < nums.length; i++){
            //如果出现次数为0,就重新给当前元素赋值
            if(sum == 0){
                cur = nums[i];
                sum = 1;
            }else{
                //如果所判断的元素等于当前存放的元素,次数就加一
                if(cur == nums[i]){
                    sum++;
                    //如果所判断的元素不等于当前存放的元素,次数就减一
                }else{
                    sum--;
                }
            }
        }
        return cur;
    }
}

测试结果

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第10张图片

Leetcode-每日一题【剑指 Offer 39. 数组中出现次数超过一半的数字】_第11张图片 

 

你可能感兴趣的:(leetcode,算法,java,数据结构)