LeetCode-169-多数元素


题意描述:

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

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


示例:

示例一:

输入: [3,2,3]
输出: 3

示例二:

输入: [2,2,1,1,1,2,2]
输出: 2

解题思路:

Alice: 找到数组中的多数元素,多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。分情况讨论一下,如果是奇数,像 ⌊ 7/2 ⌋ == 3 多数元素就是出现至少4次的元素;如果是偶数, 像⌊ 8/2 ⌋ == 4 多数元素就是出现至少 5 次的元素。也就是说无论如何也要多出一半的。
Bob:对对对,关键是怎么做呢?直接统计数组中各种元素出现的次数吧,然后遍历统计的结果,从里面找到多于一半的那个就好了。题目中说答案一定存在,那就是有且仅有的了。
Alice: 恩,用 set 统计数组中各种元素出现的次数这种代码已经写过很多次了哦。应该还有别的方法吧。
Bob: 有啊,排序吧,看到数组就想排序。O(∩_∩)O哈哈~
Alice: 排序也可以的,排完序,直接检查相邻元素重复的次数,找到一个重复超过 ⌊ n/2 ⌋ 次数的就是答案了。
Bob: 对对对,我想到可以排完序之后可以直接找到答案的方法了。你前面已经分析过了没多数元素是个数超过数组长度一半的。排完序之后,这些元素都挨在一起,连起来的长度超过数组长度的一半,一定会覆盖数组中 ⌊ n/2 ⌋ 的位置。
Alice: emmm, 拿个例子分析一下更好理解了就,无论是多数元素是最小的还是最大的,还是中间的,都一定会占据 ⌊ n/2 ⌋ 的位置。
Bob: 没错,不过排序的时间复杂度是O(n log n),应该还有更快的办法吧。

------------------------------------------------------------------------- Alice & Bob -------------------------------------------------------------------------

Alice: 我找到了,有一个叫做 Boyer-Moore 投票算法 的东西可以用来做这道题。就是 让不同的元素互相抵消,由于多数元素是占多数的,最后留下来的一定就是最多的,根据题意,最多的就是我们要的答案。
Bob: 让不同的元素互相抵消 !!! 就是挨个查呗,但是怎么抵消呢 ? 如果有三种,四种,多种元素呢 ?
Alice: 就是先拿一个元素作为 A 类,然后遍历,遇到 A 类元素,计数加一,否则减一。这样就互相抵消了,如果计数器变成零了。就从下一个元素开始重复上述操作,无论是什么样的元素都可以,反正只要不相等就可以抵消,这样一直到最后,就会剩下 答案。如果有多种元素也是一样的,答案元素是足够多的,足够抵消那些少数元素。这应该也是为什么叫做投票算法的原因。
Bob: 好像是这么回事,哎呀,这种算法最初是不是就是应用在投票结果计算上的,找到投票结果中超过半数的得票人选。
Alice: 😎😎


代码:
Python 方法一: 使用字典计数,然后遍历求解。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        cnt = {}
        for x in nums:
            # 使用字典计数
            if x in cnt:
                cnt[x] += 1
            else:
                cnt[x] = 1
        
        for x in cnt:
            # 遍历字典找到满足题意的答案
            if cnt[x] > len(nums) // 2:
                return x
           

Java 方法一: 使用 Map 计数,然后遍历返回答案。

class Solution {
    public int majorityElement(int[] nums) {
    
        Map<Integer, Integer> cnt = new HashMap<Integer, Integer>();
        for(int i=0; i<nums.length; ++i){
            if(cnt.containsKey(nums[i])){
                cnt.put(nums[i], cnt.get(nums[i]) + 1);
            }else{
                cnt.put(nums[i], 1);
            }
        }
        int answer = 0;
        for(Integer key : cnt.keySet()){
            if(cnt.get(key) > nums.length / 2){
                answer = key;
                break;
            }
        }
        return answer;
    }
}

Python 方法二: 排序 + 查找相邻的重复元素个数。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:

        if len(nums) == 1:
            return nums[0]

        nums.sort()
        cnt = 1

        for x in range(1, len(nums)):
            if nums[x] == nums[x-1]:
                cnt += 1
            else:
                cnt = 1

            if cnt > len(nums) // 2:
                return nums[x]

Java 方法二: 排序 + 相邻元素计数

class Solution {
    public int majorityElement(int[] nums) {

        if(nums.length == 1){
            return nums[0];
        }

        Arrays.sort(nums);
        int cnt = 1;
        int ans = 0;
        
        for(int i=1; i<nums.length; ++i){
        
            if(nums[i] == nums[i-1]){
                cnt += 1;
            }else{
                cnt = 1;
            }

            if(cnt > nums.length / 2){
                ans = nums[i];
                break;
            }
        }

        return ans;
    }
}

Java 方法 2.5: 排序 + 直接索引。当一个元素在数组中占据了超过一半的位置,那么无论这个元素是最大还是最小,或者不是最大也不是最小,这个元素所造成的相邻相同子数组一定会占据 ⌊ n/2 ⌋ 的位置。可以想象一下一个 超过半数 长度 的子数组在 原数组上滑动,子数组覆盖的位置一定会占据中间的那个位置。

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
    }
}

Python 方法2.5:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        nums.sort()
        return nums[len(nums) // 2]     

Python 方法三: Boyer-Moore 投票算法。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        else:

            pre = nums[0]
            cnt = 1

            for x in range(1, len(nums)):

                if cnt == 0:
                    pre = nums[x]
                    cnt = 1
                    continue

                if pre == nums[x]:
                    cnt += 1
                else:
                    cnt -= 1

            return pre

Java 方法三:

class Solution {
    public int majorityElement(int[] nums) {

        int cnt = 1;
        int pre = nums[0];

        for(int i=1; i<nums.length; ++i){

            if(cnt == 0){
                cnt = 1;
                pre = nums[i];
                continue;
            }

            if(pre == nums[i]){
                cnt += 1;
            }else{
                cnt -= 1;
            }
        }
        return pre;
    }
}

易错点:

  • 测试样例:
[3,2,3]
[2,2,1,1,1,2,2]
[2,2]
[1,2,3,2,2]
  • 答案:
3
2
2
2

总结:


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值