高效的算法求解一个序列的主元素

    题目描述:
            已知一个整数序列A={a0,a1,a2,...an-1} 其中0<=ai<n(0<=i<n).若存在
            ap1=ap2=...=apm=x且m>n/2(0<=pk<n,1<=k<=m),则称x为A的主元素。如
            A={0,5,5,3,5,7,5,5},则5为主元素,又如A={0,5,5,3,5,1,5,7},则A中没有
            主元素,若有主元素输出该元素,否则输出-1. 

     分析:因为有这个条件0<=ai<n(0<=i<n),我们可以自然而然的想到开辟一个n个长度的数组,用下标来代替0,1,2...n-1的值,数组里面自然就是存储其出现的次数咯,然后判断其个数即可,代码如下:

#include<stdio.h>
#define N 8
int A[N];
int main() {
	for(int i=0;i<N;i++){
		int k;
		scanf("%d",&k);
		A[k]++;
	}
	int ok=1;
	for(int i=0;i<N;i++){
		if(A[i]>N/2) {
			ok = 0;
			printf("%d\n",i);
			break;
		}
	}
	if(ok)
	printf("-1\n");
	return 0;
}

当然这种思路的时间复杂度为O(n),空间复杂度为O(n),能有更好的办法吗,将空间复杂度将为O(1)呢?在王道上看到这样一种思想,就是用一个count来记录num,如果下次出现的还是num,则count加一,否则减一,若为主元素,则在抵消的过程中它的count最终是大于0,而不是主元素的话在抵消的过程中会变为0。具体算法描述:

  1. 选取候选的主元素:依次扫描所给数组中的每个整数,将第一个遇到的整数num保存到c中,而用计算器count来保存出现的次数,下次再出现num则计数器加1,否则计数器减1;当计数器减到0,遇到下一个整数保存在c中,计数器重新记数为1,开始新一轮计数,即从当前位置开始重复上述过程,直到扫描完全部的数组元素。
  2. 判断c中是否是正真的主元素:再次扫描数组,统计c在数组中出现的次数是否大于n/2,大于则为中元素否则序列不存在主元素。
void Majority(int A[],int n){
	int i,c,count=1;
	c = A[0];
	for(i=1;i<n;i++){
		if(A[i] == c){
			count++;
		}else{
			if(count>0) count--;
			else {
				c = A[i];
				count = 1;
			}
		}
	}
	if(count>0){
		count = 0;
		for(i=0;i<n;i++){
			if(A[i]==c) count++;
		}
	}
	if(count>n/2) printf("%d\n",c);
	else printf("-1\n");
}

实现程序的时间复杂度为O(n),空间复杂度为O(1).

转载于:https://my.oschina.net/u/2484601/blog/808502

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值