问题:在一个规模为N的数组A[N]中,所谓主元素就是出现次数大于N/2的元素,例如 3.3.4.2.4.4.2.4.4 有一个主元素为4。
给出一个算法,如果过半元素存在,就找出来,否则给出报告,要求给出O(N)的算法。
解答:1.如果确定数组中存在主元素,则有两种解法。
一是用递归,遍历数组,第1步,如果元素的个数是1,算法退出,第2步,元素两两比较,如果两个数相同,则删去一个,如果两个数不同,则都删去,第3步,重复执行第1步。复杂度segma=n+n/2+n/4+...=O(2n)。
二是充分利用已知条件出现次数大于N/2。首先假设主元素是X,则遍历数组时出现与X相等的元素时,X出现的数目+1,不相等时,如果计数值变为1,则这个X可能不是主元素,需要将假定值更改为新出现的元素,计数值不为1时,则X出现的数目-1.遍历完后的X就是主元素。复杂度为O(n),其代码如下:
int get(int A[], int n) {
int result, cnt;
result = A[0]; cnt = 1;
for(int i=1; i<n; i++) {
if(A[i] == result) {
cnt++;
}
else if(cnt == 1) {
result = A[i];
cnt = 1;
} else {
cnt--;
}
}
return result;
}
2.如果不确定是否存在主元素。
可以将1中的解法二稍作修改,无论是否存在主元素,遍历完后的X一定是主元素的候选元,因此再次遍历数组,判断X出现的次数是否大于N/2即可。代码如下:
int get(int A[], int n) {
int result, cnt;
result = A[0]; cnt = 1;
for(int i=1; i<n; i++) {
if(A[i] == result) {
cnt++;
}
else if(cnt == 1) {
result = A[i];
cnt = 1;
} else {
cnt--;
}
}
cnt=0;
for(int i=0;i<n;i++){
if(A[i]==result)
cnt++;
}
if(cnt>(n/2))
return result;
else
return -65535;
}