數組中出現次數超過一半的數字 多種方法

傳送門

題目描述

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

分析:

1.我們首先根據數組特性,出現次數超過一半,意味着我們將數組進行排序後,中間位置的數必然是我們要尋找的數,基於這樣的想法首先得到這樣的解法,時間複雜度O(nlogn)

//數組中有一個數字出現次數超過數組長度的一半,那麼從統計意義上說,這個數必然是數組排序後的中位數
//由於先進行了排序  時間複雜度爲O(nlogn)
class Solution {
public:
    Solution()
    {
         
    }
    ~Solution()
    {
         
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int len = numbers.size();
        if(len<=0) return 0;
        sort(numbers.begin(),numbers.end());
        int solve = numbers[len/2];
        //從左右開始統計
        int ans = 0;
        for(int i = len/2,j = 0;;j++)
        {
            if(j==0) {
                ans++;
                continue;
            }
            if(i-j>=0&&numbers[i-j]==solve) ans++;
            if(i+j<len&&numbers[i+j]==solve) ans++;
            if(i-j<0&&i+j>=len) break;
        }
        if(ans>len/2) return solve;
        return 0;
    }
};

2.上述解法雖然能夠AC,但是時間複雜度爲O(nlogn),不夠優秀,這時我們能夠想到其實可以使用哈希表來統計每個數出現的次數,只需要遍歷一遍數組即可,時間複雜度爲O(n)

//利用哈希表思路,時間複雜度爲O(n)
class Solution {
private:
    map<int,int>num;
public:
    Solution()
    {
        num.clear();
    }
    ~Solution()
    {
         
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int len = numbers.size();
        if(len<=0) return 0;
        int k = len>>1;
        for(int i=0;i<len;i++)
        {
            num[numbers[i]]++;
            if(num[numbers[i]]>k) {
                return numbers[i];
            }
        }
        return 0;
    }
};

3.接下來我們思考可不可以不開闢額外空間,我們瞭解到一次快排可以得知當前主元在原數組中所處的位置,同時我們要得到下標爲數組長度一半的元素,這樣我們使用快排+二分

注意:這裏的快排使用了隨機化主元的方式,在進行randindex()函數的時候,出現過除0錯誤,這是由於rand的上界和下界相等造成的,加一個相等的特判即可。

//基於快排+二分的思想
//這種寫法是單路快排,更加好的方法三路快排
class Solution {
public:
    Solution()
    {
        
    }
    ~Solution()
    {
        
    }
    int randindex(int l ,int r)
    {
        if(l==r) return l;
        srand(time(NULL));
        return (int)rand()%(r-l)+l;
    }
    int quick_sort(int l, int r,vector<int> &num)
    {
        //找到主元所在位置   隨機化主元
        int i = l ;
        int j = r;
        int index = randindex(l,r);
        int temp = num[index];
        swap(num[index],num[l]);
        while(i!=j)
        {
            while(i<j&&num[j]>=temp) j--;
            while(i<j&&num[i]<=temp) i++;
            swap(num[i],num[j]);
        }
        swap(num[l],num[i]);
        return i;
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int len = numbers.size();
        if(len<=0) return 0;
        //進行多次快排尋找位於len/2的元素
        int l = 0 , r = len-1,solve;
        while(l<=r)
        {
            int index = quick_sort(l,r,numbers);
            if(index==len/2) {
                solve = numbers[index];
                break;
            }
            else if(index>len/2) r = index-1;
                 else if(index<len/2) l = index+1;
        }
        int ans = 0;
        for(int i=0;i<len;i++)
            if(numbers[i]==solve) ans++;
        if(ans>len/2) return solve;
        return 0;
    }
};

4.最後是三路快排實現的方法,三路快排返回一個區間範圍,表示當前主元及與當前主元相等的元素都聚集的一個範圍,當中間元素在這個範圍內時,則說明我們找到解,之後在進行判斷即可,反之,我們對區間再進行二分

//二分+三路快排
class Solution {
public:
    Solution()
    {
        
    }
    ~Solution()
    {
        
    }
    int randindex(int l,int r)
    {
        srand(time(NULL));
        if(l==r) return l;
        return rand()%(r-l)+l;
    }
    //進行三路快排,每次都將重複的主元都放到一起,返回這個區間
    pair<int,int> ThreeWaysQuick_sort(int l,int r,vector<int>& vec)
    {
        //隨機化選取主元
        int index = randindex(l,r);
        int temp = vec[index];
        //利用三個指針實現三路快排
        //p1指向第一個是temp的數,方便與後面小於temp的數進行交換
        //p2指向最後一個是temp的數,一旦發現一個小於temp的數,馬上與p1指針指向的數進行交換
        //p3指向大於temp的第一個數
        int p1 = l , p2 = l ,p3 = r;
        while(p2<=p3)
        {
            if(vec[p2]==temp) {
                p2++;
            }
            else if(vec[p2]<temp) {
                swap(vec[p1],vec[p2]);
                p1++;
                p2++;
            }
            else if(vec[p2]>temp) {
                swap(vec[p3],vec[p2]);
                p3--;
            }
        }
        if(vec[p3]==temp) p3++;
        return make_pair(p1,p2);
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int len = numbers.size();
        if(len<=0) return 0;
        int l = 0 , r = len - 1 , solve;
        while(l<=r)
        {
            //三路快排,每次都將相同的數放到一起,所以得到的是一個當前主元的區間範圍,如果返回的區間範圍包括了中間值,那麼結束二分
            pair<int,int> index;
            index = ThreeWaysQuick_sort(l,r,numbers);
            if(len/2>=index.first && len/2<=index.second) {
                solve = numbers[len/2];
                break;
            }
            else if(len/2<index.first) {
                r = index.first-1;
            }
            else if(len/2>index.second) {
                l = index.second+1;
            }
        }
        int ans = 0;
        for(int i = len/2 , j = 0; ; j++ )
        {
            if(j==0) {
                ans++;
                continue;
            }
            if(i-j>=0) {
                if(solve==numbers[i-j]) ans++;
            }
            if(i+j<len) {
                if(solve==numbers[i+j]) ans++;
            }
            if(i-j<0&&i+j>=len) break;
        }
        if(ans>len/2) return solve;
        return 0;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章