1370---数组中出现次数超过一半的数字

题目描述:

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

 

输入:

每个测试案例包括2行:

第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。

第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。

 

输出:

对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。

 

样例输入:
9
1 2 3 2 2 2 5 4 2
样例输出:
2

解题报告:

方法一:

数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。

基于这个思路,我们不难写出如下代码:

 

#include<iostream>
using namespace std;

int a[100001];
int main()
{
	int n,i,temp,num;
	while(cin>>n)
	{
		cin>>a[0];
		temp=a[0];
		num=1;
		for(i=1;i<n;i++)
		{
			cin>>a[i];
			if(num==0)
			{
				temp=a[i];
				num=1;
			}
			else
			{
				if(temp==a[i]) num++;
				else num--;
			}
		}
		num=0;
		for(i=0;i<n;i++)
			if(a[i]==temp) num++;
		if(num*2>n) cout<<temp<<endl;
		else cout<<-1<<endl;
	}
	return 0;
}

 

 注:

在上述代码中,有两点值得讨论:

(1)      我们需要考虑当输入的数组或者长度无效时,如何告诉函数的调用者输入无效。

(2)本算法的前提是输入的数组中的确包含一个出现次数超过数组长度一半的数字。如果数组中并不包含这么一个数字,那么输入也是无效的。因此在函数结束前我还加了一段代码来验证输入是不是有效的。

 

 

方法二:

先说在这道题目上能成功的:

  我们首先对数组进行排序,因为要找出数目超过一半的数,因此,如果存在,那么这个数组的中间值肯定是这个数。比如

  1 2 2 2 1 或者 1 1 2 2 2 或者 2 2 2 3 3,中间的肯定是我们要找的数。

  而如果不存在,那么进行一次o(n)的扫描即可。因此我们的算法时间复杂度为快排+一次遍历,o(nlogn)+o(n)。

 

 

posted @ 2014-12-30 14:54  zhoudan  阅读(147)  评论(0)    收藏  举报