1. 程式人生 > >尋找大小為n的陣列中出現次數超過n/2的那個數

尋找大小為n的陣列中出現次數超過n/2的那個數

       問題描述: 在一個大小為n的陣列中,其中有一個數出現的次數超過n/2,求出這個數。這題看似很簡單,但是找到最優解不容易,一般情況我們首先想到最笨的方法,每選一個數,遍歷一次陣列,複雜度O(N^2),或者先排序再找那個數,複雜度一般為O(NlgN),或者用hash,時間複雜度O(N),空間複雜度需要看輸入的資料規模,空間複雜度O(N)。所以這些都不是最優解,我們先分析一下這個題目,設該數出現的次數為x,則x滿足,n/2+1<= x <=n;所以我們可以想到如果該數和其餘的數全部相抵消的話,至少還剩1個,我們從前往後遍歷,設key為第一個數,key出現的次數為ntime,初始化為1,代表key出現了一次,從前往後,如果某個數不等於key,則他倆抵消,key的出現次數減一,如果等於key,則key的出現次數加1,如果key的出現次數變成了0,則說明key已經用完了,所以需要重新初始化key為另一個數,再重複以上步驟,因為一定有一個數大於n/2,所以遍歷到最後剩下的那個數,就是要求的數。

#include <iostream>
#include <vector>
using namespace std;
/*在大小為n的陣列中尋找次數超過n/2的數*/
int find_data(vector<int> &arry)
{
    int ntime = 0; //表示其中某一個數出現的次數
    int result;
    for(unsigned int i = 0; i < arry.size(); i++) {
        if(ntime == 0) {   //在i前面的數全部刪除完,或者起始的時候,將arry[i]放入結果
              result = arry[i];
              ntime = 1;  //arry[i]出現的次數為1;
        } else { //如果前面有數,就說明result還沒抵消完
              if(result == arry[i]) //如果相等result出現的次數+1
                ntime++;
              else
                ntime--;  /*如果此時的arry[i]不等於result,則它們兩個抵消,result的次數減一,由與那個數大於n/2所以它抵消不完,ntime最小為1
                            也就是說這個數出現的次數是大於等於n/2+1*/
        }
    }
    return result;
}
int main()
{
    vector<int> arry; 
    int n;
    cin>>n;
    for(int i = 0; i < n; i++) {
            int d;
        cin>>d;
        arry.push_back(d);
    }
    int result = find_data(arry);
    cout<<result;
    return 0;
}