LeetCode229:Majority Element II

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

Note: The algorithm should run in linear time and in O(1) space.

Example 1:

Input: [3,2,3]
Output: [3]

Example 2:

Input: [1,1,1,3,3,2,2,2]
Output: [1,2]

LeetCode:链接

这题是LeetCode169:Majority Element的升级版,要求时间复杂度O(n),空间复杂度O(1),也就是不能排序、不能hash,只能用我们的摩尔投票。

首先要明确的是最多有2个解why?   因为出现次数大于n/3,则至少有n/3+1次,若有3个解,则总数应该为 3 * (n/3+1)次,也就是 n+3 >n与题目不符。因为可能会有两个解,所以我们需要两个候选元素a和b,以及他们相应的计数cnt_a,cnt_b。

初始时将a和b任意的设置为不同的数,将cnt_a和cnt_b分别设置为0,然后遍历数组。

同样的,设当前的元素为x,

  • 若x==a 则cnt_a++
  • 若x==b则cnt_b ++
  • 若cnt_a ==0 则 a = x, cnt_a =1
  • 若cnt_b ==0 则 b = x, cnt_b =1
  • 否则 cnt_a– , cnt_b–

最后算出来的a,b在遍历一遍数组,判断其是否真的 > n/3次

为什么这样是对的呢?

对于有2个解的情况,设解为a和b, 显然a和b不会被少于n/3个元素给抵消掉,所以2个解的情况是OK的。

那么1个解的情况呢?除了元素a(a是解)外,剩下的元素不到2n/3个(这里设为m个,m < 2n/3 ),而这m个元素中,至多有m/2个元素会抵消元素a(因为我们有两个计数的哇),换句话说,能抵消a的元素总数 <=  m/2 < n /3 ,也就是说元素a最后一定会得到保留。

对于无解的情况,最后验证了是否合法,也没问题。

class Solution(object):
    def majorityElement(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        if not nums:
            return []
        candidate1, candidate2, count1, count2 = 0, 0, 0, 0
        for i in range(len(nums)):
            if candidate1 == nums[i]:   # 投A
                count1 += 1
            elif candidate2 == nums[i]:  # 投B
                count2 += 1 
            elif count1 == 0:   # 此时A,B都不投,检查是否有票数为0情况,如果为0,则更新候选人
                count1 = 1
                candidate1 = nums[i]
            elif count2 == 0:    # 此时A,B都不投,检查是否有票数为0情况,如果为0,则更新候选人
                count2 = 1
                candidate2 = nums[i]
            else:          # 此时两个候选人的票数都大于1,且当前A和B都不投,那么A,B对应的票数都要--;
                count1 -= 1
                count2 -= 1
        # 上一轮遍历找出了两个候选人,但是这两个候选人是否均满足票数大于N/3仍然没法确定,需要重新遍历,确定票数
        count1, count2 = 0, 0
        for num in nums:
            if num == candidate1:
                count1 += 1
            elif num == candidate2:
                count2 += 1
        res = []
        if count1 > int(len(nums)/3):
            res.append(candidate1)
        if count2 > int(len(nums)/3):
            res.append(candidate2)

        return res

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值