【LeetCode 169】多数元素(Python)

  • Post author:
  • Post category:python


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

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

示例 1:

输入: [3,2,3]

输出: 3

二、解题思路1:(哈希表)

使用字典自带的get方法可以统计词频。所以把数组遍历按key元素,value词频放入字典。

代码:所用的是哈希算法。时间复杂度为O(n)空间复杂度为O(n)。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        zd={}
        for i in nums:
	        zd[i]=zd.get(i,0)+1
	        if zd[i] > len(nums)/2:return i

下面所有提到的解题方法(算法)都来自于官方给出的参考答案。

作者:LeetCode-Solution

链接:https://leetcode-cn.com/problems/majority-element/solution/duo-shu-yuan-su-by-leetcode-solution/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

三、排序

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

四、分治(较复杂,难懂,可不掌握)

思路

  1. 如果数 a 是数组 nums 的众数,如果我们将 nums 分成两部分,那么 a 必定是至少一部分的众数。
  2. 我们可以使用反证法来证明这个结论。假设 a 既不是左半部分的众数,也不是右半部分的众数,那么 a 出现的次数少于 l / 2 + r / 2 次,其中 l 和 r 分别是左半部分和右半部分的长度。由于 l / 2 + r / 2 <= (l + r) / 2,说明 a 也不是数组 nums 的众数,因此出现了矛盾。所以这个结论是正确的。
  3. 这样以来,我们就可以使用分治法解决这个问题:将数组分成左右两部分,分别求出左半部分的众数 a1 以及右半部分的众数 a2,随后在 a1 和 a2 中选出正确的众数。

算法

我们使用经典的分治算法递归求解,直到所有的子问题都是长度为 1 的数组。长度为 1 的子数组中唯一的数显然是众数,直接返回即可。如果回溯后某区间的长度大于 1,我们必须将左右子区间的值合并。如果它们的众数相同,那么显然这一段区间的众数是它们相同的值。否则,我们需要比较两个众数在整个区间内出现的次数来决定该区间的众数。

代码

class Solution:
    def majorityElement(self, nums, lo=0, hi=None):
        def majority_element_rec(lo, hi):
            # base case; the only element in an array of size 1 is the majority
            # element.
            if lo == hi:
                return nums[lo]

            # recurse on left and right halves of this slice.
            mid = (hi-lo)//2 + lo
            left = majority_element_rec(lo, mid)
            right = majority_element_rec(mid+1, hi)

            # if the two halves agree on the majority element, return it.
            if left == right:
                return left

            # otherwise, count each element and return the "winner".
            left_count = sum(1 for i in range(lo, hi+1) if nums[i] == left)
            right_count = sum(1 for i in range(lo, hi+1) if nums[i] == right)

            return left if left_count > right_count else right

        return majority_element_rec(0, len(nums)-1)

五、Boyer-Moore 投票算法(和四分治类似难懂,但最好可以掌握)

思路

如果我们把众数记为 +1+1,把其他数记为 -1−1,将它们全部加起来,显然和大于 0,从结果本身我们可以看出众数比其他数多。

算法

Boyer-Moore 算法的本质和方法四中的分治十分类似。我们首先给出 Boyer-Moore 算法的详细步骤:

  1. 我们维护一个候选众数 candidate 和它出现的次数 count。初始时 candidate 可以为任意值,count 为 0;
  2. 我们遍历数组 nums 中的所有元素,对于每个元素 x,在判断 x 之前,如果 count 的值为 0,我们先将 x 的值赋予 candidate,随后我们判断 x:
  3. 如果 x 与 candidate 相等,那么计数器 count 的值增加 1;
  4. 如果 x 与 candidate 不等,那么计数器 count 的值减少 1。
  5. 在遍历完成后,candidate 即为整个数组的众数。

代码

class Solution:
    def majorityElement(self, nums):
        count = 0
        candidate = None

        for num in nums:
            if count == 0:
                candidate = num
            count += (1 if num == candidate else -1)

        return candidate



版权声明:本文为Lucy_R原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。