高效的算法求解一個序列的主元素

    題目描述:
            已知一個整數序列A={a0,a1,a2,...an-1} 其中0<=ai<n(0<=i<n).若存在
            ap1=ap2=...=apm=x且m>n/2(0<=pk<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中沒有
            主元素,如有主元素輸出該元素,不然輸出-1. 算法

     分析:由於有這個條件0<=ai<n(0<=i<n),咱們能夠天然而然的想到開闢一個n個長度的數組,用下標來代替0,1,2...n-1的值,數組裏面天然就是存儲其出現的次數咯,而後判斷其個數便可,代碼以下:數組

#include<stdio.h>
#define N 8
int A[N];
int main() {
	for(int i=0;i<N;i++){
		int k;
		scanf("%d",&k);
		A[k]++;
	}
	int ok=1;
	for(int i=0;i<N;i++){
		if(A[i]>N/2) {
			ok = 0;
			printf("%d\n",i);
			break;
		}
	}
	if(ok)
	printf("-1\n");
	return 0;
}

固然這種思路的時間複雜度爲O(n),空間複雜度爲O(n),能有更好的辦法嗎,將空間複雜度將爲O(1)呢?在王道上看到這樣一種思想,就是用一個count來記錄num,若是下次出現的仍是num,則count加一,不然減一,若爲主元素,則在抵消的過程當中它的count最終是大於0,而不是主元素的話在抵消的過程當中會變爲0。具體算法描述:code

  1. 選取候選的主元素:依次掃描所給數組中的每一個整數,將第一個遇到的整數num保存到c中,而用計算器count來保存出現的次數,下次再出現num則計數器加1,不然計數器減1;當計數器減到0,遇到下一個整數保存在c中,計數器從新記數爲1,開始新一輪計數,即從當前位置開始重複上述過程,直到掃描徹底部的數組元素。
  2. 判斷c中是不是正真的主元素:再次掃描數組,統計c在數組中出現的次數是否大於n/2,大於則爲中元素不然序列不存在主元素。
void Majority(int A[],int n){
	int i,c,count=1;
	c = A[0];
	for(i=1;i<n;i++){
		if(A[i] == c){
			count++;
		}else{
			if(count>0) count--;
			else {
				c = A[i];
				count = 1;
			}
		}
	}
	if(count>0){
		count = 0;
		for(i=0;i<n;i++){
			if(A[i]==c) count++;
		}
	}
	if(count>n/2) printf("%d\n",c);
	else printf("-1\n");
}

實現程序的時間複雜度爲O(n),空間複雜度爲O(1).it

相關文章
相關標籤/搜索