摩尔投票法(过半众数算法)

1. 题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

假设数组非空,如果不存在满足条件的数字,返回-1

思考题:

假设要求只能使用 O ( n ) O(n) O(n) 的时间和额外 O ( 1 ) O(1) O(1) 的空间,该怎么做呢?

样例1
输入:

5
1 2 1 1 3

输出:

1

样例2
输入:

5
1 1 2 2 3

输出:

-1

2. 摩尔投票法

摩尔投票算法的时间和空间都很低,时间复杂度为O(n),空间复杂度为O(1)。

算法原理
每次从数组中找出一对不同的元素,将它们从数组中删除,直到遍历完整个数组。由于这道题已经说明一定存在一个出现次数超过一半的元素,所以遍历完数组后数组中一定会存在至少一个元素。

算法步骤

  1. 定义全局技术器变量 c n t cnt cnt(初值为 0 0 0),当前答案变量 v a l val val。开始遍历数组,当前元素为 x x x
  2. c n t = = 0 cnt == 0 cnt==0,则 v a l = x , c n t + + val = x,cnt++ val=x,cnt++;(假设答案是基佬,有唯一的一个房间,基佬看到房间没人,就进去,基佬数+1)。
  3. c n t ! = 0 cnt != 0 cnt!=0,且 v a l = = x val == x val==x,则 c n t + + cnt++ cnt++;(房间里有基佬,来了新的基佬,基佬喜欢和基佬在一起,就进了房间,基佬数+1)。
  4. c n t ! = 0 cnt != 0 cnt!=0,且 v a l ! = x val != x val!=x,则 c n t − − cnt-- cnt;(房间里有基佬,这时候来了一个妹子,妹子从房间里带走一个基佬,基佬数-1)。
  5. 数组每个元素按照 1   4 1~4 1 4 操作走一遍,最后的 v a l val val 就代表算法求得的答案值(但数组不一定有大于一半的元素存在)。

无解情况
如果数组中不存在大于数组长度一半的元素,如样例2中所示,则拿着算法求得的 v a l val val 去一个个对比数组元素,如果超过了 n / 2 n/2 n/2 的数量,则说明有解,解就是 v a l val val;否则说明无解。

3. 代码

#include <iostream>
using namespace std;

const int N = 2010;
int n;
int a[N];

int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++) scanf("%d", &a[i]);
	
	int cnt = 0, val;
	for (int i = 0; i < n; i++)
	{
		if (!cnt) val = a[i], cnt++;
		else if (val == x) cnt++;
		else cnt--;
	}
	
	cnt = 0;
	for (int i = 0; i < n; i++) if (a[i] == val) cnt++;
	
	if (cnt > n / 2) printf("%d\n", val);
	else puts("-1");
	
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁头娃撞碎南墙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值