169题 多数元素
找出n个元素的数组中出现次数大于n/2的元素。
属于经典简单的数组题,但是方法多,还是列举一下,顺便把摩尔投票法学习一下。
方法一:排序法。
库函数。用sort函数排序,那么中间位置一定是答案。时间复杂度为
O(nlogn),空间复杂度为O(logn)
方法二:计数法。
库函数。这个思路是最简单最不需要脑子的,但是如果直接遍历去count,时间复杂度太高会超时提交失败。但如果转化为集合,利用集合中元素唯一的性质就可以降低至少n/2的时间复杂度。可以提交成功。
但是使用库函数的我觉得都没有意义... 只能说可以作为练习理解。
方法三:哈希表。
典型的哈希思想例子,创建一个哈希表存储数组中元素出现的次数,再创建集合利用集合中元素唯一的性质遍历哈希表的key查找符合要求的value. 时间复杂度和空间复杂度都是O(n)
这个才能叫真正的算法叭,但是方法一使用排序其实也有它的思路,应该学习。
class Solution:
def majorityElement(self, nums: List[int]) -> int:
dict_helper = {}
set_nums = set(nums)
for each in nums:
dict_helper[each] = dict_helper.get(each, 0) + 1
for each_key in set_nums:
if dict_helper[each_key] > len(nums)/2:
return each_key
方法四:摩尔投票法。
思路是抵消,candidate设置为nums[0],count=0. 如果下一个值等于candidate count+=1,否则count-=1。那么当count再次为0,它的意义是前面【一段】中的众数个数为len/2,那么就可以抛过去不再考虑,重新定义candidate为下一个值,到最后count必为非负!绝妙
注意它是用来找多数元素而非众数的哈。只有有 > len/2 这个性质才能这样去用算法。
class Solution:
def majorityElement(self, nums: List[int]) -> int:
candidate = nums[0]
count = 0
for each in nums:
if count == 0: candidate = each
if each == candidate: count += 1
else: count -= 1
return candidate
229题 求众数2
这是摩尔投票法的一个进阶版。特地翻出来做了一下,比传统的要多检验数目 > len/3 和 cand1 = cand2 两个过程。我写出这个:
class Solution:
def majorityElement(self, nums: List[int]) -> List[int]:
cand1, cand2 = nums[0], nums[0]
count1, count2 = 0, 0
for each in nums:
if count1 == 0: cand1 = each
if count2 == 0: cand2 = each
count1 += 1 if cand1 == each else -1
count2 += 1 if cand2 == each else -1
#与传统摩尔投票法的区别是这里需要检验每个数是否超过n/3个
count1 = count2 = 0
for each in nums:
if each == cand1: count1 += 1
if each == cand2: count2 += 1
res = [i for i,c in zip((cand1, cand2), (count1, count2)) if c > len(nums)/3]
return list(set(res)) #保证不重复
没提交我就发现了盲点:这样cand1和cand2不就完完全全一样嘛??怎么可以找得到不相等的两个众数... 发现问题出现在我写的if判断是分离的,其实应该赋值给一个之后就直接结束,这里的逻辑判断不可分离!否则就会cand12完全同步
另外这里还要强调一点:不分离的逻辑判断也意味着cand12不相撞,count1+1时count2不会-1
class Solution:
def majorityElement(self, nums: List[int]) -> List[int]:
cand1, cand2 = nums[0], nums[0]
count1, count2 = 0, 0
for each in nums:
if cand1 == each: count1 += 1
elif cand2 == each: count2 += 1
elif not count1: cand1, count1 = each, 1
elif not count2: cand2, count2 = each, 1
else:
count1 -= 1
count2 -= 1
#与传统摩尔投票法的区别是这里需要检验每个数是否超过n/3个
count1 = count2 = 0
for each in nums:
if each == cand1: count1 += 1
if each == cand2: count2 += 1
res = [i for i,c in zip((cand1, cand2), (count1, count2)) if c > len(nums)/3]
return list(set(res)) #保证不重复