题目:已知一个整数序列 A=(a0, a1, …, a(n-1)),其中 0<=a(i)<n(0<=i<n)。若存在 a(p1)=a(p2)=…=a(pm)=x 且 m>n/2(0<=p(k)<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 中没有主元素。假设 A 中的 n 个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出 A 的主元素。若存在主元素,则输出该元素;否则输出 -1。
代码如下:
方法一(做题时自己花费时间最短的方法):运用两层循环,每一次都遍历一遍数组,看计数是否大于n/2,满足就输出(时间复杂度为O(N*N))
int Majority(int A[],int n)
{
for(i=0;i<n;i++)
{
count=0;
for(j=0;j<n;j++)
{
if(i!=j&&A[i]==A[j])
count++;
}
if(count>n/2)
return A[i];
}
return -1;
}
方法二:运用快排思想,然后再查找中间的数即可 (直接查找中间的数是因为主元素的个数超过一半,所以如果存在主元素,在数组n/2处一定是主元素)(时间复杂度为 (快排的时间复杂度) O(nlogn))
给出快排代码:排好后在主函数中查询A[n/2]即可,此代码为快排核心代码
//快速排序分割函数
int Partition(SqList &L,int low,int high)
{
int pivotekey = L.data[low]; //保存枢轴
while (low<high)
{
while (low < high&&L.data[high] >= pivotekey) --high;
L.data[low] = L.data[high];
while (low < high&&L.data[low] <= pivotekey) ++low;
L.data[high] = L.data[low];
}
L.data[low] = pivotekey;
PrintList(L);
return low;
}
// 快速排序 升序
void QuickSort(SqList &L, int low, int high)
{
if (low < high)
{
int pivotloc = Partition(L,low,high);
QuickSort(L,low,pivotloc-1);
QuickSort(L, pivotloc + 1, high);
}
}
方法三(次优解):计数排序思想,用空间换时间,运用一个辅助数组,把出现的元素存到对应数组位置,然后遍历找出最大的,看是否满足个数大于n/2即可(时间复杂度O(n)空间复杂度O(n))
int Major(int A[],int n){
int k,*p,max;
p=(int *)malloc(sizeof(int)*n)
for(k=0,k<n,k++) p[k]=0; //将申请的动态数组清0
max=0;//max初始为0
for(k=0,k<n,k++)
{
p[A[k]]++ //将数组A中位置为k的元素放到p数组的A[k]位置上
if(p[A[K]]>P[max]) max=A[k];//记录次数最多的数,A[K]为p数组的位置,也是对应的个数最多的元素
}
if(p[max>n/2])return max;
else return -1;
}
方法四:(最优解)但是是不容易想到的,没看到过一定想不到的。这种方法的原理是如果一个数组中存在一个主元素(个数大于n/2),如果两个不相等的元素两两抵消,那么最终一定剩下的是主元素。
简单的说就一个大小为n数组中存在一个元素的个数大于n/2,则如果用这个数组中其他元素和该主元素进行抵消的话,最后剩下的一定是主元素,因为主元素个数最多。
该方法可以在O(n)的时间内找到主元素。(时间复杂度O(n),空间复杂度O(1))
int Majority(int A[], int n){
int i,c,count=1;
c=A[0];
for(i=1;i<n;i++)//查找候选元素
if(A[i]==c)
count++;//对A中的候选元素进行计数
else
if(count>0)
count--;
else //更换主元素,重新计数
{
c=A[i];
count=1;
}
if(count>0)
for(i=count=0; i<n; i++)
if(A[i]==c)
count++;
if(count>n/2) return c;
else return -1;
}
算法为自己学习使用,多理解思想,有错误之处还请多多包涵!!!