主元素問題的多種解法


Part -1:版權聲明:

本文大部分代碼來自這篇博文

Part 0:啥是主元素問題

給一個有\(n\)個元素的數列,保證有一個數\(a\)出現的次數超過50%,求這個數

Part 1:桶計數做法

桶計數做法是出現一個數,就把這個數出現次數+1,很好懂:

#include <bits/stdc++.h>
using namespace std;
int ans[10001],n,t;
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>t;
        ans[t]++;
    }
    for(int i=0;i<10001;i++)
        if(ans[i]>n/2){
            cout<<i;
            break;
        }
}

很好懂,時間復雜度\(O(N + M)\)
但是,一旦利用桶的思想,就不可避免的遇到一個問題:空間
比如我給你的數是這樣的:

1 12398517923876091 1000 1000000 10000000000 9999999 2345234618 1239 102358 12398517923876091 12398517923876091 12398517923876091 12398517923876091 12398517923876091 12398517923876091

請問你要開多大的空間?12398517923876091個數組
好,有的同學說可以離散化,我再給你一組數據:

1 2 3 4 5 6 ... LONG_MAX 1 1 1 ...(LONG_MAX/2個1)

從1到LONG_MAX全部給你,你怎么做?你繼續離散化啊?你離散啊你離散啊你離散啊~
(別問我為什么數據這么毒瘤,我自己出數據就是這么毒瘤)

Part 2: 排序做法

顯然,若一個數列存在主元素,那么這個主元素在排序后一定位於\(\frac{n}{2}\)的位置
那么我們又有想法了:

#include <bits/stdc++.h>
using namespace std;
int n,a[10001];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    sort(a,a+n);//C++ STL自帶排序函數
    cout<<a[n/2+1-1];//減1是因為這里數組從a[0]開始用
    return 0;
}

看起來不錯!\(O(NlogN)\)的復雜度可還行?
於是,一旦有\(NlogN\),就一定有人想出\(N\)。有嗎?還真的有——

Part 3:終極做法

這個數列有個特性:由於主元素的出現的次數超過50%,那么在不斷的消掉兩個不同的元素之后,最后一定剩下主元素
有的同學會問了:如果數列長度為偶數呢?
我說這位同學,請 你 審 題

給一個有\(n\)個元素的數列,保證有一個數\(a\)出現的次數超過50%,求這個數

再讀一次:

保證有一個數\(a\)出現的次數超過50%

還不懂?再讀一次:

超過50%

再不懂?滾!
輸入時判斷與上一次保存的輸入是否相同,如不同則刪除兩數,這里用棧來實現。

#include<stdio.h>
int n,q[10001],top=0,a;
int main()
{
    scanf("%d",&n);
    while(n--)scanf("%d",&a),q[top++]=a,top=(top>1&&(q[top-1]!=q[top-2]))?top-2:top;
    printf("%d",q[top-1]);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM