3种算法求主元素

文章目录

  • 问题描述
    • 法一:分治法
      • 复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)
    • 法二
      • 复杂度 O ( n ) O(n) O(n)
      • 代码
    • 法三
      • 复杂度 O ( n ) O(n) O(n)
      • 代码

问题描述

主元素是一个数组里面个数大于一半的数。若有则返回主元素,没有则返回-1;

法一:分治法

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

用分治法寻找其主元素。设 x x x为其主元素,原数组分成两半,则 x x x T [ 1 : n / 2 ] T[1:n/2] T[1:n/2] T [ n / 2 + 1 : n ] T[n/2+1:n] T[n/2+1:n]的主元素。

若两个数组均没有主元素,则原数组没有主元素。

之后,为了判定 x x x是否为 T [ i : j ] T[i:j] T[i:j]的主元素,需要对 T [ i : j ] T[i:j] T[i:j]进行一次线性扫描即可。

T ( n ) = { O ( 1 ) n < = 4 2 T ( n / 2 ) + O ( n ) n > 4 T(n) = \begin{cases}O(1) & n<=4 \\2T(n/2)+O(n) &n>4\end{cases} T(n)={O(1)2T(n/2)+O(n)n<=4n>4
解得 T ( n ) = O ( n log ⁡ n ) T(n) = O(n\log n) T(n)=O(nlogn)

代码

#include
#define max_len 50
using namespace std;
int a[max_len];
int de(int l, int r){
	if((r+1-l)<=4){
		if((r+1-l)==1){
			return a[l];
		}
		else if((r+1-l)==2){
			if(a[r]==a[l]){
				return a[l];
			}
			else return -1;
		}
		else if((r+1-l)==3){
			//cerr<<"in 3---"<
			if(a[l]==a[l+1])return a[l];
			else if(a[l]==a[l+2])return a[l];
			else if(a[l+1]==a[l+2])return a[l+1];
			else return -1;
		}	
		else{
			int t[4] = {a[l],a[l+1],a[l+2],a[l+3]};
			//for(int i = 0;i<4;i++) cerr<
			//cout<
			sort(t,t+4);
			//for(int i = 0;i<4;i++) cerr<
			//cout<
			if(t[1]==t[2]) return t[1];
			else return -1;
		}
	}
	int c = (l+r)/2;
	int ans1 = de(l,c);
	//cerr<<"ans1------:"<
	int ans2 = de(c+1,r);
	//cerr<<"ans2------:"<
	int ans = -1;
	if(ans1!=-1){
		int cnt = 0;
		//cerr<<"l:"<
		for(int i = l;i<=r;i++) if(a[i]==ans1)cnt++;
		//cerr<<"cnt1---:"<
		if(cnt>(r+1-l)/2) ans = ans1;
	}
	if(ans2!=-1){
		int cnt = 0;
		//cerr<<"l:"<
		//for(int i = l;i<=r;i++) cout<
		for(int i = l;i<=r;i++) if(a[i]==ans2)cnt++;
		//cerr<<"cnt2---"<
		if(cnt>(r+1-l)/2) ans = ans2;
	}
	return ans;
}
int main(){
	int n;
	cin>>n;
	for(int i = 0;i<n;i++)cin>>a[i];
	int l = 0;
	int r = n-1;
	int ans = de(0,n-1);
	cout<<ans;
	return 0;
}

法二

复杂度 O ( n ) O(n) O(n)

1 ≤ i ≤ n / 2 1\leq i \leq n/2 1in/2,比较

T [ 2 ∗ i − 1 ] 与 T [ 2 ∗ i ] , 当 T [ 2 ∗ i − 1 ] = T [ 2 ∗ i ] 时,将 T [ 2 ∗ i ] T[2*i-1]与T[2*i],当T[2*i-1]=T[2*i]时,将T[2*i] T[2i1]T[2i],T[2i1]=T[2i]时,将T[2i]存入另一个数组Q中,否则不操作。

x x x T [ 1 : n ] 的主元素,则 x 是 Q 的主元素或 T [ n ] 是 T [ 1 : n ] 的主元素。 T[1:n]的主元素,则x是Q的主元素或T[n]是T[1:n]的主元素。 T[1:n]的主元素,则xQ的主元素或T[n]T[1:n]的主元素。

代码

复杂度分析:
T ( n ) = { O ( 1 ) n ≤ c T ( n / 2 ) + O ( n ) n > c T(n) = \begin{cases} O(1) &n\leq c\\ T(n/2) + O(n) &n>c \end{cases} T(n)={O(1)T(n/2)+O(n)ncn>c
解得 T ( n ) = O ( n ) T(n) = O(n) T(n)=O(n).
代码如下:

#include
#define max_len 50
using namespace std;
int a[max_len];
int cnt,c_ans;
int select(int t[],int len){
	if(len%2==1){
		int tmp = t[len];
		for(int j = 1;j<=len;j++){
			if(tmp == t[j]) c_ans++;
		}
		if(c_ans>len/2){
			c_ans = 0;
			return tmp;
		}
	}
	if(len==0) return -1;
	if(len==1) return t[len];
	cnt = 0;
	int q[max_len] = {0};
	memset(q,0,sizeof(q));
	for(int i = 1;i<=len/2;i++){
		if(t[2*i] == t[2*i-1]){
			cnt++;	
			q[cnt] = t[2*i];
		}
	}
	return select(q,cnt);
} 
int main(){
	int n;
	cin>>n;
	for(int i = 1;i<=n;i++){
		cin>>a[i];
	}
	int ans = select(a,n);
	if(ans==-1)cout<<-1;
	else{
		for(int j = 1;j<=n;j++){
			if(ans == a[j]) c_ans++;
		}
		if(c_ans>n/2)cout<<ans;
		else cout<<-1;
	}
	return 0;
} 

法三

复杂度 O ( n ) O(n) O(n)

t m p 初始化为 a [ 0 ] tmp初始化为a[0] tmp初始化为a[0],之后遍历数组,若 a [ i ] = = t m p a[i] == tmp a[i]==tmp,则 c n t = c n t + 1 , cnt = cnt + 1, cnt=cnt+1,否则 c n t = c n t − 1 , 当 c n t = 0 时,更新 t m p 为此时扫描到的 a [ i ] cnt = cnt - 1,当cnt = 0时,更新tmp为此时扫描到的a[i] cnt=cnt1,cnt=0时,更新tmp为此时扫描到的a[i].

之后,检查 c n t cnt cnt的值,若 c n t ≠ 0 cnt \neq 0 cnt=0,此时对应的 t m p tmp tmp值就是主元素。 c n t ≤ 0 cnt\le 0 cnt0则说明没有主元素。
复杂度分析:
只遍历了一次数组,所以
T ( n ) = O ( n ) T(n) = O(n) T(n)=O(n)

代码

#include
#define max_len 50
using namespace std;
int a[max_len];
int main(){
	int n;
	cin>>n;
	for(int i = 0;i<n;i++)cin>>a[i];
	int cnt = 1;
	int it = 1;
	int tmp1 = a[0];
	while(it<n){
		int tmp2 = a[it++];
		if(tmp1==tmp2)cnt++;
		else cnt--;
		if(cnt<=0){
			tmp1 = tmp2;
			cnt = 0;
		}
	}
	cout<<endl;
	if(cnt!=0)cout<<tmp1;
	else cout<<-1;
	return 0;
} 


你可能感兴趣的:(算法分析,算法,c++,开发语言)