数组主元素问题

8 篇文章 0 订阅

首先感谢mxw老铁,提出了这个问题。

问题描述

【问题描述】

已知一个整数序列A长度为N其中若存在a且a的个数大于N/2则称为A的主元素

例如0 5 5 3 5 7 5 5 则为主元素 5

又如0 5 5 3 5 1 5 7则中没有主元素。

假设中的个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出的主元素。若存在主元素则输出该元素否则输出


【输入形式】

一个整数数组
【输出形式】

主元素
【样例输入】

0 5 5 3 5 7 5 5
【样例输出】

5

一、思考临界时的情况

临界时,即某一元素恰好为主元素

我们拿十个数字为例。

比如

1 2 3 2 4 2 5 2 6 2

显然这是十个数字,只要在任意一个地方插入2这字数字 那么2就成了这个数组的主元素

二、想方法

(1)笨笨的方法:

                暴力二重循环

int time
for(int i=0;i<n;i++)
{
    time=0;
    for(int j=0;j<n;j++)
    {
        if(a[i]==a[j])
        {
            time++;
        }
    }
    if(time>n/2)
    printf("yes");
}
    

        显然不可能用这种聪(ben)明(dan)方法,时间复杂度为O(n^2);

(2)稍微聪明点的方法

        假设主元素为m,那么想,数组中与m相同的必然比与m不同的多

        也就是

        相同-不相同>0

        于是我们想到设置一个计数器count(默认值为1),去记录与m相同的次数。

        相同加一,不相同减一,最后观看count是否大于0

        如果大于零,那么就是主元素。

        但似乎和笨蛋方法一样,也需要二重循环,时间复杂度还是O(n^2)

        我们需要做出优化。

(3)聪明的方法

        二重循环就是老慢牛,谁用谁拉稀。

        为此,我们想,能否用一个循环,只遍历一遍数组,就干出来它。

先假设这个数组就是有主元素的

        我们想,最极致的例子就是 相同的比不相同的多一个(奇数)

        我们依次把数组中从头到尾,任意两个不相同的都干掉,那么最后剩下的那一个一定是主元素。

        不太极致一些,相同的比不相同的多两个,那么都干掉以后,就剩下两个一模一样的,那么,该数值的元素就是主元素

        以此类推,会有更不极致的例子,最后剩下若干个一模一样的,那么同样的,这个元素就是主元素。

        为此我们借用方法二的计数器方法,相同count+=1,不相同count-=1,当为零时说明相同和不相同的抵消了,则前面的全扔掉,从下一个开始重复上叙述过程。

#include<stdio.h>
int main()
{
	int a[100];
	int i=0,n;
	while(1)
{
	scanf("%d",&a[i]);
	i++;
	char c=getchar();
	if(c=='\n')break;
}
	n=i;
	int m,count;
	m=a[0];
	count=1;
	for(i=1;i<n;i++)
	{
		if(m==a[i])
		{
			count++;
		}
		else 
		{
			if(count>0)
			{
				count--;
			}
			else
			{
				m=a[i];
				count=1;
			}
		}
	}
	printf("%d是主元素",m);
	return 0;
}

       然后,我们抛弃假设,如果不知道数组是不是存在主元素呢

        直接在下面再用m遍历一遍,判断次数是否大于n/2;

        这样的时间复杂度依然是O(2N)=O(N),

#include<stdio.h>
int main()
{
	int a[100];
	int i=0,n;
	while(1)
{
	scanf("%d",&a[i]);
	i++;
	char c=getchar();
	if(c=='\n')break;
}
	n=i;
	int m,count,x;
	m=a[0];
	count=1;
	for(i=1;i<n;i++)
	{
		if(m==a[i])
		{
			count++;
		}
		else 
		{
			if(count>0)
			{
				count--;
			}
			else
			{
				m=a[i];
				count=1;
			}
		}
	}
	x=0;
	for(i=0;i<n;i++)
	{
		if(m==a[i])
		{
			x++;
		}
	}
	if(x>n/2)
	printf("%d",m);
	else
		printf("-1");
	return 0;
}

        

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值