劍指offer | 面試題39:數組中出現次數超過一半的數字

轉載本文章請標明作者和出處
本文出自《Darwin的程序空間》
本文題目和部分解題思路來源自《劍指offer》第二版

在這裏插入圖片描述

開始行動,你已經成功一半了,獻給正在奮鬥的我們

題目

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

解題分析

這個問題,解決不難,有很多種方案可以解決這個問題:

比如說我們可以使用哈希表(也就是HashMap),鍵爲出現的數字,值爲出現的次數,每遍歷一個元素就把它的次數加1,直到有一個數字出現的次數大於數據的size,這個數就是衆數,這種方式很好理解,時間複雜度爲O(n),但是需要的空間也是O(n);

再比如我們可以使用排序數組的方法進行,排序後的數組,數組的中間數即爲衆數(出現最多的那個數),數組排序的時間複雜度爲O(nlgn)

我們還可以使用partiton函數的做法,時間複雜度爲O(n),但是會修改原有的數據結構,需要的可以自行去百度一下這種算法,但是面試的時候需要詢問面試官是否可以修改原有的數據結構


筆者推薦的是一種叫做投票算法的實現;

就比如我們小學的時候選舉班長,選舉的時候如果有一個人獲取了全班一半以上人支持的話,他就當選了;
比如參加選舉的同學有四個[小A、小B、小C和小D]
如果最後是小A當選的話,那麼一定小B、小C和小D加起來的票數還沒有小A多,所以每次如果叫一個選擇小B或小C或小D的和選擇小A的出教室,最後教室裏面剩下的一定是選擇小A的,那麼如果是每次叫兩個選擇不一樣的人出教室,最後剩下的那個也一定是選擇小A的。道理很簡單,小B、小C和小D加起來都沒人家多,現在還有可能小B和小C和小D自行消耗,就更不可能有小A的多了。
在這裏插入圖片描述

(圖片來源於網絡)

這就是投票算法。

所以我們只需要記住當前遍歷數組的數字middle,和它出現的次數count,如果有和它不一樣的,就把count–,如果count小於1,那麼就換下一個數字,如果出現的和這個數字一樣的,就把count加1,最後剩下的一定是數組中出現次數超過一半的數字,也就是衆數。

但是要注意,這種做法,數組裏面一定要有衆數纔行,就算沒有衆數,這種算法也會給你一個答案的,如果還要判斷數組裏面是否存在衆數,那推薦你使用哈希表。

代碼(JAVA、python實現)

ps:這裏筆者使用的jdk爲1.8,python3.7版本

  • java實現
public class Offer39_Mode {

    public static void main(String[] args) {
        System.out.println(mode(new int[]{1, 1, 1, 2, 2, 3, 4, 5, 2, 1, 1, 1, 1}));
    }

    public static int mode(int[] arr) {
        if (Objects.isNull(arr) || arr.length == 0) {
            return -1;
        }
        // 目前出現次數最多的數字
        int middle = arr[0];
        // 統計出現次數,用來抵消其他的數字
        int count = 1;
        for (int i = 1; i < arr.length; i++) {
            int num = arr[i];
            if (count == 0) {
                middle = num;
                count = 1;
            } else if (num == middle) {
                count++;
            } else {
                count--;
            }

        }
        return middle;
    }
}

  • python實現
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        x = 1
        y = nums[0]

        for i in range(len(nums)):
            if i == 0:
                continue
            if x == 0:
                y = nums[i]
            if nums[i] != y:
                x -= 1
            else:
                x += 1
        return y
喜歡的朋友可以加我的個人微信,我們一起進步
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章