在下面的解决方案工作下面的算法拼图和调试工作。我的困惑和疑问是,我们怎样才能始终保证元素的计数出现超过n / 3次有正数?还有另外2n / 3个元素可以使它数为负数?但我试过,它总是在我的样本中工作。如果有人能帮忙澄清,那就太好了。
以下是问题陈述和我的代码/测试用例
给定一个大小为n的整数数组,找到所有出现超过⌊n /3⌋次的元素。算法应该在线性时间和O(1)空间中运行。
def majorityElement(nums):
if not nums:
return []
count1, count2, candidate1, candidate2 = 0, 0, 0, 0
for n in nums:
if n == candidate1:
count1 += 1
elif n == candidate2:
count2 += 1
elif count1 == 0:
candidate1, count1 = n, 1
elif count2 == 0:
candidate2, count2 = n, 1
else:
count1, count2 = count1 - 1, count2 - 1
return [n for n in (candidate1, candidate2) if nums.count(n) > len(nums) // 3]
if __name__ == "__main__":
# print majorityElement([1,2,1,3,1,5,6])
print majorityElement([2,3,1,2,1,3,1,5,5,1,6])
提前谢谢,
林
答案 0 :(得分:3)
从概念上讲,我们重复对列表中应用缩减操作,该操作涉及删除三个成对不同的项目。这个特殊的代码在线进行减少,因此到目前为止减少的列表可以用两个不同的元素及其相应的计数来描述(因为如果有第三个元素与其他两个元素不同,那么我们可以减少)。最后,我们考虑最多两个元素发生超过n / 3次。
正确性证明的有趣部分是一个引理,每当我们执行此减少操作时,在旧列表中发生更多n / 3次的任何元素在新列表中发生的次数超过n'/ 3次,其中n是旧列表的长度,n'= n-3是新列表的长度。这通过归纳确保最终列表包含在初始列表中出现超过n / 3次的所有元素(但当然最终列表仅包含两个不同的元素)。
引理的证明是,如果一个项目在旧列表中出现n次k次,那么在最坏的情况下,它会在新列表中的n-3中出现k-1次,如果k / n> ; 1/3,然后
(k-1) n
(k-1)/(n-3) = -------
(n-3) n
k (n-3) + 3 k - n
= -----------------
(n-3) n
(k/n - 1/3)
= k/n + 3 -----------
n-3
> 1/3.