LeetCode-劍指Offer-39-數組中出現次數超過一半的數字


題意描述:

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。你可以假設數組是非空的,並且給定的數組總是存在多數元素。

注意 1 <= 數組長度 <= 50000


示例:

輸入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
輸出: 2

解題思路:

Alice: 這道題好面熟啊。
Bob: 那可定是之前做過了,有什麼想法嗎 ?
Alice: 可以用Python裏面的字典計算每個數字出現的次數,然後找到出現次數最多的那個就好了,時間複雜度應該是O(n), 空間複雜度是O(k) k是不同數字的個數。
Bob: 還可以先排序,然後檢查相鄰相同元素的個數,找到最大的那個,時間複雜度應該是O(nlogn + n) 空間複雜度是O(1)
Alice: 我怎麼總想起來快速排序呢 ?能借鑑裏面的做法嗎,出現次數超過數組長度一半。那排好序後這些元素可定會覆蓋數組中間的位置啊。
Bob: 那就是說,排序後直接返回 nums.length / 2 位置的元素就行了 ?
Alice: 是啊,這樣時間複雜度就下降到O(n * log n)了。哦哦哦,我想起來,還有一種算法,是O(n) 的時間複雜度,O(1) 的空間複雜度。
Bob: 我也想起來了,好像叫什麼投票算法。不過我自己把它叫做 “羣雄逐鹿” 算法。 想象一下,東漢末年,羣雄並起,有一個兒數組,數組中的不同的元素表示不同的派系,相鄰位置的元素之間戰爭不斷,只有相鄰且相同的元素才能共存,相鄰不相同的元素只能同歸於盡,問最後誰能問鼎中原呢 ?
Alice: hhh, 你這不就是羣毆嗎,只有相鄰且相同的元素才能積蓄,相鄰不相同的元素相互抵消。這樣從前到後遍歷數組,最後留下來的就多數,而且是數量最多的。你發現了沒有,這個投票算法不僅僅可以求數量超過數組元素個數一般的,也可以求更一般的結果,可以求數組中相同數字最多的那個。
Bob: 👍👍😎😎
Alice: 還是不會用 Java 中的字典呀 ,🤷‍♀️


代碼:

Python 方法一: 字典計數,然後求出現次數最多的。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:

        cnt = {}
        for x in nums:
            if x not in cnt:
                cnt[x] = 1
            else:
                cnt[x] += 1
        
        maxCnt = 0
        ret    = 0 
        for x in cnt.keys():
            if cnt[x] > maxCnt:
                maxCnt = cnt[x]
                ret = x
        
        return ret

Java 方法二: 排序 + 檢查相鄰元素。

class Solution {
    public int majorityElement(int[] nums) {

        Arrays.sort(nums);
        int ret    = nums[0];
        int cnt    = 1;
        int maxCnt = 1;

        for(int i=1; i<nums.length; ++i){
            if(nums[i-1] == nums[i]){
                cnt += 1;
            }else{
                if(cnt > maxCnt){
                    maxCnt = cnt;
                    ret  = nums[i-1];
                }
                cnt = 1;
            }
        }

        if(cnt > maxCnt){
            maxCnt = cnt;
            ret  = nums[nums.length-1];
        }

        return ret;
    }
}

Java 方法二: 多於數組一半的元素連起來一定會覆蓋數組中間的那個位置,也就是排序後nums.length / 2 的位置

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
    }
}

Java 方法三: “功過相抵,逐鹿中原” ?

class Solution {
    public int majorityElement(int[] nums) {

        int cnt = 1;
        int pre = nums[0];

        for(int i=1; i<nums.length; ++i){

            if(cnt == 0){                // 新的一輪爭霸
                cnt = 1;
                pre = nums[i];
                continue;
            }

            if(nums[i] == pre){
                cnt += 1;                 // "招兵"
            }else{
                cnt -= 1;                 // “打仗”
            }
        }

        return pre;
    }
}

易錯點:

  • 一些測試點:
[1,2,3,2,2,2,5,4,2]
[1]
[1,1]
[1,2,1]
[2,3,3]
2
1
1
1
3

總結:


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