杭电 1029
Ignatius and the Princess IV
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32767 K (Java/Others)
Total Submission(s): 21212 Accepted Submission(s): 8788
Problem Description
"OK, you are not too bad, em... But you can never pass the next test." feng5166 says.
"I will tell you an odd number N, and then N integers. There will be a special integer among them, you have to tell me which integer is the special one after I tell you all the integers." feng5166 says.
"But what is the characteristic of the special integer?" Ignatius asks.
"The integer will appear at least (N+1)/2 times. If you can't find the right integer, I will kill the Princess, and you will be my dinner, too. Hahahaha....." feng5166 says.
Can you find the special integer for Ignatius?
Input
The input contains several test cases. Each test case contains two lines. The first line consists of an odd integer N(1<=N<=999999) which indicate the number of the integers feng5166 will tell our hero. The second line contains the N integers. The input is terminated by the end of file.
Output
For each test case, you have to output only one line which contains the special number you have found.
Sample Input
51 3 2 3 3111 1 1 1 1 5 5 5 5 5 571 1 1 1 1 1 1
Sample Output
351
分析:
典型的主元素问题,即给定一个元素集合,求其中出现次数大于总数一半的元素。
关于主元素问题有很多种解法;
在此列出几种我知道的解法:
1、暴力求解:枚举集合中的每个元素,遍历求个数,最后比较得出主元素,时间复杂度O(n*n)
2、桶排序:创建一个大数组,用小标指代元素,下标所指的数字代表该元素出现的次数,读入数据时,例如,读入了3,那么array[3]++; 数据读完后一次遍历即可得出主元素,缺点,若集合中出现较大的元素,则数组需要创建的很大,空间复杂度高,优化办法:用map建立映射关系。
3、查找最大连续相同序列,将集合内的数据进行排序,从头开始遍历,若连续遇到相同元素的次数大于(n+1)/2 次,该元素便为主元素。为了降低时间复杂度,使用scanf读入数据,排序使用快速排序。
4、线性解法:根据:“在元素数组中,删去不同的两个元素,数组的主元素保持不变”这一结论,可以不断缩小问题规模,利于求解。
关于主元素的线性解法,引自百度:
置变量Seed用于存储当前候选元素,初始化为数组首元素a[0];
设置变量count用于控制候选元素,初始化为1;
从第二个元素a[1]开始遍历数组,并与Seed相比较:相同,则count加1,读入下一个元素;
不同,则count减1,读入下一个元素:相当于删去两个不同元素,缩小问题规模;如果count小于0则Seed不是主元素候选,读入下一个元素,count加1
。这样一次遍历之后,得到的Seed就是主元素的候选;但因为最终得到的Seed元素有可能是序列最末位的两个元素之一,所以还需要验证。我们再次遍历数组,得到Seed出现的次数,与总数的一半比较来验证。
附上方法3的AC代码:
#include<algorithm>
#include<iostream>
using namespace std;
int shuru[1000005];
int cmp(const void *a,const void* b)
{
return *(int *)a-*(int *)b;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%d",&shuru[i]);
qsort(shuru,n,sizeof(int),cmp);
int count=1;
int flag=shuru[0];
for(int i=1;i<n;i++)
{
if(shuru[i]==flag)
{
count+=1;
}
else
{
if(count>=(n+1)/2)
break;
flag=shuru[i];
count=1;
}
}
printf("%d\n",flag);
}
return 0;
}