主元素是一个数组里面个数大于一半的数。若有则返回主元素,没有则返回-1;
用分治法寻找其主元素。设 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;
}
对 1 ≤ i ≤ n / 2 1\leq i \leq n/2 1≤i≤n/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[2∗i−1]与T[2∗i],当T[2∗i−1]=T[2∗i]时,将T[2∗i]存入另一个数组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]的主元素,则x是Q的主元素或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)n≤cn>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;
}
取 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=cnt−1,当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 cnt≤0则说明没有主元素。
复杂度分析:
只遍历了一次数组,所以
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;
}