1. 程式人生 > >求一個數組中出現次數超過n/3的數(c++實現)

求一個數組中出現次數超過n/3的數(c++實現)

題目要求如下:

令A是一個長度為n的正整數序列。試設計一個時間 和空間複雜度分別為O(n)和O(1) 的演算法,判斷A中 是否存在這樣的元素x,x在序列中出現次數超過n/3。 若存在這樣的x,則將其輸出。

實現思路:

、BM(Boyer-Moore Majority Vote Algorithm)投票法:設定一個計數器,在遍歷陣列的時候,如果是這個數,則計數器加1,否則減1,該方法用來計數超過一半的數非常方便。在這裡我們改進一下BM投票計數法:設定兩個計數器,如果是兩個數中的一個,則對應的計數器加1,如果不是這兩個數中的任何一個,則兩個計數器都減1。如果計數器為0了,則統計當前這個數。那麼如果一個數出現次數超過1/3,則最後必然出現在統計的數中,但是我們不確定得到的這兩個數出現次數是否超過1/3,因此最後需要驗證一下。該演算法的時間複雜度是O(n),空間複雜度是O(1)。

證明思路:

求陣列中多於一半的或者是多於1/3的全部數字都可以用這種方法解決

這裡給你一個數組,要你求出所有出現數量多於 ⌊ n/3 ⌋的數字,這題方法簡單,但是原理非常複雜,,首先用兩個數a,b,n1,n2來分別記錄峰1,峰2,峰1的數量,峰2的數量,可以證明,當求 所有多於⌊ n/m ⌋的數的時候,只要定義(m-1)個不同的數字,以及(m-1)個不同的計數,將所有計數初始化為0,所有數字初始化為不同值,記住,一定要是不同值,但是可以是任何值,要不然不能保證計算過程中所有數字的不同,最後可能導致result裡面新增多個相同的數字

證明方法是,當發現num[i]和a1,a2,…am-1裡面一個數字相同的時候,假設是ak,將nk加一,當發現num[i]和任何一個數字都不同的時候,替換掉任何一個nk==0的數字,也就是ak=num[i],nk++,就這樣一直計算下去,可以證明,當計算完成的時候,a1,a2…am-1裡面一定存在所有出現次數多於⌊ n/m ⌋的數,這時只要重新檢查a1,a2…am-1看那個出現的次數多於⌊ n/m ⌋就行了

這裡簡單的證明一下,假設有m個區間,每個區間有t個數,那麼n可表示成n=m*t+z,這裡z=0~m-1,這裡假設有一組多於⌊ n/m ⌋,設這組為A,那麼他的數量num(A)>=t+1,<=n,可以證明,每一個A裡面的數可以和m-1個其他數消除,每m-1個其他數可以消除一個A,我們現在來證明當演算法進行到最後A一定消除不完。

我們使A的數量最少,為t+1,非A的數儘可能的多,為(m-1)*t+m-1-1=n-t-1,非A的數能消耗A的數最多為⌊ (m-1)*t+m-1-1 ⌋=⌊ t-1/(m-1) ⌋<t+1,因此A的數最後一定有剩,A的數有剩則其一定存在於a1,a2…am-1裡面,否則其一定被消耗完了,這和假設不符,其他各個多於⌊ n/m ⌋的數也可以同樣證明,

程式碼:

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int a=0;
        int b=1;
        int ca=0;
        int cb=0;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]==a)
                ca++;
            else if(nums[i]==b)
                cb++;
            else if(ca==0)
            {
                a=nums[i];
                ca++;
            }
            else if(cb==0)
            {
                b=nums[i];
                cb++;
            }
            else
            {
                ca--;
                cb--;
            }
        }
        ca=0;
        cb=0;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]==a)
                ca++;
            else if(nums[i]==b)
                cb++;
        }
        vector<int> result;
        if(ca>nums.size()/3)
            result.push_back(a);
        if(cb>nums.size()/3)
            result.push_back(b);
        return result;
    }
};