在刷 LeetCode 简单题的时候碰到了一道题,LeetCode 第 169 题 ,描述很简单:
- 给定一个大小为
n
的数组nums
,返回其中的多数元素。多数元素是指在数组中出现次数大于⌊ n/2 ⌋
的元素。 - 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
其实一开始想到的就是排序找中位数,或者找众数,但是看题解之后才发现有更简单的 solution 。
Boyer-Moore 投票算法(摩尔投票算法),在题解的评论里看到一个对这个算法的描述,感觉非常贴切:同归于尽消杀法。其实核心思想非常简单:先维护一个数字和它出现的次数,当下个数字与这个数相同时,它出现的次数加 1
,否则减 1
,如果出现次数变为了 0
,则将这个数字换成下一个遇到的数字。因为总是存在出现次数大于 ⌊ n/2 ⌋
的元素,所以最后必定会得到一个数组,并且这个数字的出现次数大于 0
。
用 Golang 实现 Boyer-Moore 投票算法 解决上面的题目:
func majorityElement(nums []int) int {
res, quantity := nums[0], 1
for i := 1; i < len(nums); i++ {
if res == nums[i] {
quantity++
} else {
if quantity == 0 {
res = nums[i]
} else {
quantity--
}
}
}
return res
}
虽然感觉这个算法的适用范围比较窄,不能找众数,只能找到 出现次数大 n/2 的元素 ,但是思想确实非常巧妙,对应解决这一类问题来说效率应该是最高的,时间复杂度为 \(O(n)\) ,空间复杂度为 \(O(1)\) 。
评论