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