LeetCode求众数:摩尔投票法golang实现

17 篇文章 0 订阅

给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。

LeetCode原题:

作者:wotxdx
链接:https://leetcode-cn.com/problems/majority-element-ii/solution/liang-fu-dong-hua-yan-shi-mo-er-tou-piao-fa-zui-zh/

摩尔投票法,解决的问题是如何在任意多的候选人中,选出票数超过一半的那个人。注意,是超出一半票数的那个人。

摩尔投票法分为两个阶段

                       抵消阶段计数阶段。

抵消阶段:两个不同投票进行对坑,并且同时抵消掉各一张票,如果两个投票相同,则累加可抵消的次数;

计数阶段:在抵消阶段最后得到的抵消计数只要不为 0,那这个候选人是有可能超过一半的票数的,为了验证,则需要遍历一次,统计票数,才可确定。

摩尔投票法经历两个阶段最多消耗 O(2n) 的时间,也属于 O(n)的线性时间复杂度,另外空间复杂度也达到常量级。

如果最后得到的可抵消票数是 0 的话,那他已经无缘票数能超过一半的那个人了。因为本来可能有希望的,但是被后面的一张不同的票抵消掉了。所以,在这里可以直接返回结果,无需后面的计算了。

如果最后得到的抵消票数不为 0 的话,那说明他可能希望的.

理解摩尔投票法之后,我们再回到题目描述,题目可以看作是:在任意多的候选人中,选出票数超过⌊ 1/3 ⌋的候选人。

显然,票数超过1/3的最多只可以有2个候选人

如果至多选一个代表,那他的票数至少要超过一半(⌊ 1/2 ⌋)的票数;

如果至多选两个代表,那他们的票数至少要超过 ⌊ 1/3 ⌋ 的票数;

如果至多选m个代表,那他们的票数至少要超过 ⌊ 1/(m+1) ⌋ 的票数。

所以以后碰到这样的问题,而且要求达到线性的时间复杂度以及常量级的空间复杂度,直接套上摩尔投票法。


我这里只是把原作者的代码重构了一下,把投票和计数部分单独封装了两个函数:

func majorityElement(nums []int) []int {
	// 创建返回值
	result := make([]int, 0)
	if nums == nil || len(nums) == 0 {
		return result
	}
	//投票和计数两个阶段
	cand1, cand2 := voteStage(nums)
	return countStage(cand1, cand2, nums)
}

投票函数:

/*投票阶段
初始化两个候选人 candidate,以及他们的计数票*/
func voteStage(nums []int) (cand1, cand2 int) {
	cand1, cand2 = nums[0], nums[0]
	count1, count2 := 0, 0
	//摩尔投票法
	for _, num := range nums {
		// 投票
		if cand1 == num {
			count1++
			continue
		}
		if cand2 == num {
			count2++
			continue
		}
		if count1 == 0 {
			cand1 = num
			count1++
			continue
		}
		if count2 == 0 {
			cand2 = num
			count2++
			continue
		}
		count1--
		count2--
	}
	return cand1, cand2
}

计数阶段:统计两个候选人出现的次数,并判断出现的次数是否超过总数的1/3.

func countStage(cand1, cand2 int, nums []int) (result []int) {
	count1, count2 := 0, 0
	for _, num := range nums {
		if cand1 == num {
			count1++
		} else if cand2 == num {
			count2++
		}
	}
	//判断候选人的出现频率是否大于1/3
	if count1 > len(nums)/3 {
		result = append(result, cand1)
	}
	if count2 > len(nums)/3 {
		result = append(result, cand2)
	}
	return result
}

测试:

import (
    "fmt"
)

func main(){
    candidate := []int{7, 2, 7, 2, 7, 5, 7, 2, 2, 2, 9}
	fmt.Println(majorityElement(candidate))

}

输出:

>>[7 2]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值