多数排序在leetcode只是一个简单题,但是衍生出来的多种解法却非常有意思
首先是最容易想到的hash和排序算法,接着是
随机化
从概率来讲一个随机挑选一个元素并验证都很大概率是众数
func majorityElementRandom(nums []int) int {
n := len(nums)
mc := n / 2
for {
candidate := nums[rand.Int63n(int64(n))]
count := 0
for _, num := range nums {
if num == candidate {
count++
}
if count > mc {
return candidate
}
}
}
}
分治法
分治法是基于数组的众数一定来自于左右子数组的众数之一,因此将数组递归分治最后聚合得到最终的数组多数
func majorityElement(nums []int) int {
var f func(lo, hi int) int
f = func(lo, hi int) int {
// 如果仅有一个元素,那么该元素就是众数
if lo == hi {
return nums[lo]
}
// 递归数组左右边,找到左右众数
mid := lo + (hi-lo)/2
left := f(lo, mid)
right := f(mid+1, hi)
// 若左右众数相等,直接返回
if left == right {
return left
}
// 统计左右众数的个数
var lc, rc int
for i := lo; i <= hi; i++ {
switch nums[i] {
case left:
lc++
case right:
rc++
}
}
// 比较个数,返回最终众数
if lc > rc {
return left
}
return right
}
return f(0, len(nums)-1)
}
Boyer-Moore
这是本题中最优雅的解法了。设众数+1,非众数-1,那么即使最开始选上的不是众数,由于众数是超过半数的,那么一定在某个众数,发生计数为0的情况,那么此时选上的数就是众数
func majorityElement(nums []int) int {
var count, candidate int
for _, num := range nums {
if count == 0 {
candidate = num
}
if candidate == num {
count++
} else {
count--
}
}
return candidate
}
https://leetcode.cn/problems/majority-element/description/