LeetCode高频100题刷题记录之——找出众数

1 题目描述

大小为 n n n的数组中存在一个数量大于 ⌊ n / 2 ⌋ ⌊ n/2 ⌋ n/2的众数,找出这个数。

2 哈希表查找法

遍历这个数组,统计每个数出现的次数,返回次数最大的那个数。

python代码实现:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        num_dict = {}
        for num in nums:
            if num in num_dict:
                num_dict[num] += 1
            else:
                num_dict[num] = 1
        return max(num_dict, key = num_dict.get)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

缺点是需要额外占用存储空间。

3 随机化方法

因为数组中必然存在一个唯一的众数,可以随机从数组中选取一个数,判断其是否是众数,如果不是则返回。

python代码实现:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        len_num = len(nums)
        while 1:
            n = random.choice(nums)
            count = 0
            for num in nums:
                if n == num:
                    count += 1
            if count >= len_num / 2:
                return n
                break

空间复杂度只使用了额外的n和count,因此是 O ( 1 ) O(1) O(1),最坏时间复杂度是 O ( ∞ ) O(∞) O(),但一般不会出现,期望时间复杂度是 O ( n ) O(n) O(n)

4 Boyer-Moore 投票法

看了官方题解以后学到的新方法,感觉思路非常不错,而且只需要遍历一次,也不需要很多的额外空间,思想值得学习。

思路在于,我们已经明确地知道数组中存在一个大于 ⌊ n / 2 ⌋ ⌊ n/2 ⌋ n/2的数,这也就意味着假如我们把这个数单独记为一类,其他数单独记为另一类,按照少数服从多数的原则,最后留下来的肯定是这个众数。

python代码实现:

说明,初始的时候投票结果count是0,占优势的对象也初始化成0,假如count是0,说明现在各方处于互相僵持阶段,你和我的数量相互抵消,因此下一个数就可以视为是优势数,将其赋给candidate,假如下一个数和candidate不一致,那二者肯定不会投相同的票,因此count减1。遍历整个数组以后,最后肯定是占数组一半以上的众数取得压倒性优势,其他数要么彼此内耗,要么和众数互相抵消,最后众数一定有盈余。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        candidate = 0
        count = 0
        for num in nums:
            if count == 0:
                candidate = num
            if candidate == num:
                count += 1
            else:
                count -= 1
        return candidate

5 递归分治思想

看了官方题解以后才发现,这题可以用递归里面的分治思想来做。

其原理是,假如某个数是数组里的众数,将这个数组分成两半,这个数也必然至少是这两半里面一半的众数,因此可以用递归,每次都找出每一半的众数,再判断哪一个是整个的众数,最后就能返回整个数组的众数了。

python代码实现如下:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        else:
            a = self.majorityElement(nums[0 : len(nums) // 2])
            b = self.majorityElement(nums[len(nums) // 2 : ])
            num_a = 0
            num_b = 0
            for num in nums:
                if num == a:
                    num_a += 1
                elif num == b:
                    num_b += 1
            if num_a > num_b:
                return a
            else:
                return b

时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),因为会进行两次长度为 n n n的判断,同时求解两个长度为 n / 2 n/2 n/2的子问题,因此时间复杂度也比较大。

同时,因为递归要使用额外的栈空间(这里留坑,以后学习),因此需要空间复杂度 O ( l o g n ) O(log n) O(logn)(进行了 O ( l o g n ) O(log n) O(logn)次递归操作)。

其他方法还有排序法,比较简单,就不写了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值