劍指Offer——數組中出現次數超過一半的數字

題目描述

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。

方法一

最先想到的是對數組記性排序,然後遍歷數組找出出現次數超過數組長度的一半的數。該方法的時間複雜度就是排序用的時間,即最快的排序算法的時間複雜度O(nlogn)。
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if( numbers.empty() )
            return 0;
        sort(numbers.begin(),numbers.end());
        int i = 0;
        int size = numbers.size();
        for( int j=0;j<size;j++ )
        {
            if( numbers[j] != numbers[i] )
                i = j;
            if( j-i+1 > size/2 )
                return numbers[j];
        }
        return 0;
    }
};
如果一個數字出現的次數超過數組長度的一半,那麼在排序後,這個數字應該位於數組的中間位置,所以可以在對數組進行排序後,直接取中間位置的數字,但需要考慮不存在出現的次數超過數組長度的一半的數字的情況,所以在取中間位置的數字後,需要遍歷一遍統計其出現次數進行檢驗。(改進:也可以利用快排思想,利用遞歸找到處於數組中間位置的數字,而不需要對整個數組排序排序完)
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if(numbers.empty())
            return 0;
        sort(numbers.begin(), numbers.end());
         
        int size = (int)numbers.size();
        int num = numbers[size/2];
        int count = 0;
        for(int i=0; i<size; ++i)
        {
            if(num == numbers[i])
                ++count;
        }
        if(count > size/2)
            return  num;
        else
            return  0;
    }
};

方法二

利用map記錄每個數字以及數字出現的次數,其中key爲數組元素值,value爲此數出現的次數。遍歷一遍數組,統計每個數出現的次數,判斷有沒有出現次數超過數組長度的一半的值。此時的時間複雜度爲 O(n),空間複雜度爲O(n)。個人比較喜歡這種方法,實現起來簡單,不過空間複雜度大一些。
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if( numbers.empty() )
            return 0;
        int size = numbers.size();
        unordered_map<int, int> record;
        for( int i=0;i<size;i++ )
        {
            record[numbers[i]]++;
            if( record[numbers[i]] > size/2 )
                return numbers[i];
        }
        return 0;
    }
};

方法三

        如果一個數字出現的次數超過數組長度的一半,所以這個數字出現的次數比其他數出現的次數的總和還多。考慮每次刪除兩個不同的數,那麼在剩下的數中,出現的次數仍然超過總數的一般,不斷重複該過程,排除掉其他的數,最終找到那個出現次數超過一半的數字。這個方法的時間複雜度是O(N),空間複雜度是O(1)。

       換個思路,這個可以通過計數實現,而不是真正物理刪除。在遍歷數組的過程中,保存兩個值,一個是數組中數字,一個是出現次數。當遍歷到下一個數字時,如果這個數字跟之前保存的數字相同,則次數加1,如果不同,則次數減1。如果次數爲0,則保存下一個數字並把次數設置爲1,由於我們要找的數字出現的次數比其他所有數字出現的次數之和還要多,如果存在,那麼要找的數字肯定是最後一次把次數設爲1時對應的數字。

注意:找到數字後需要檢驗其正確性。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if( numbers.empty() )
            return 0;
        int times = 0;
        int res = 0;
        int size = numbers.size();
        for( int i=0;i<size;i++ )
        {
            if( times == 0 )
            {
                res = numbers[i];
                times ++;
            }
            else if( numbers[i] == res )
                times++;
            else
                times--;
        }
        times = 0;
        for( int i=0;i<size;i++ )
            if( numbers[i] == res )
                times++;
        if( times > size/2 )
            return res;
        else
            return 0;
    }
};
發佈了52 篇原創文章 · 獲贊 54 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章