<strong>一、题目描述:</strong>
二、算法思想:
本算法的巧妙之处在于充分利用主元素的定义,即在序列中个数超过半数的元素。那么在动态统计的过程中,主元素出现的频率要最大可能的大于1/2。由于是动态统计,所以可能在局部范围内可能出现误判,当主元素在序列分布不均时,可能一开始出现误判,但最终是会被纠正的,这个是可以通过数学证明一下。由于是必要条件,所以在最后还要进行充分性验证。
具体算法可以分为以下两步:
1)选取候选主元素:一次扫描所给数组中的每个整数,将第一个遇到的整数Num保存到c中,记录Num的出现次数为1。若遇到的下一个整数仍为Num,则计数加1,否则计数减1。当计数减到0时,将遇到的下一个整数保存到c中,计数重新记为1,开始新一轮的计数(此处是算法的关键,通过这种方式模拟主元素出现的频率应该大于1/2),即从当前位置开始重复上述过程,直到扫描完全部数组元素。(必要性)
2)判断c中元素是否是真正的主元素:再次扫描该数组,统计c中元素出现的次数,若大于n/2,则为主元素,否则序列中不存在主元素。(充分性)
三、核心代码:
int Main_Search(int A[],int n)
{
int i;
int c;//用c来保存候选主元素
c=A[0];//设置A[0]为候选主元素
int counter=1;//,counter用来计数
for(i=1;i<n;i++)
{
if(A[i]==c)
counter++;//对A中候选主元素计数
else
{
if(counter>0)//处理不是候选主元素的情况
counter--;
else
{
c=A[i];//更换候选主元素,重新计数
counter=1;
}
}
}
for(i=0;i<n;i++)
{
if(A[i]==c)
counter++;//统计候选主元素的实际出现次数
}
if(counter>n/2)
return c;//确认候选元素
else
return -1;//不存在主元素
}
四、完整代码:
#include<stdio.h> int Main_Search(int A[],int n); void Print(int A[],int n); int main() { //int A[]={0,5,5,3,5,7,5,5}; int A[]={1,2,3,0,1,1,0,0,1,1,1}; int n=sizeof(A)/sizeof(int); Print(A,n); printf("%d\n",Main_Search(A,n)); return 0; } int Main_Search(int A[],int n) { int i; int c;//用c来保存候选主元素 c=A[0];//设置A[0]为候选主元素 int counter=1;//,counter用来计数 /*必要条件,动态统计,主元素出现的频率应该大于1/2*/ for(i=1;i<n;i++) { if(A[i]==c) counter++;//对A中候选主元素计数 else { if(counter>0)//处理不是候选主元素的情况 counter--; else { c=A[i];//更换候选主元素,重新计数 counter=1; } } } /*充分性验证,保证主元素出现的频率大于1/2*/ for(i=0;i<n;i++) { if(A[i]==c) counter++;//统计候选主元素的实际出现次数 } if(counter>n/2) return c;//确认候选元素 else return -1;//不存在主元素 } void Print(int A[],int n) { int i; for(i=0;i<n;i++) printf("%-3d",A[i]); printf("\n"); }
五、测试分析:
时间复杂度O(n),空间复杂度1