面試 19:輸出數(shù)組中出現(xiàn)次數(shù)超過一半的數(shù)字(劍指 Offer 26 題)

面試 19:輸出數(shù)組中出現(xiàn)次數(shù)超過一半的數(shù)字(劍指 Offer 26 題)

上一篇推文給大家留下的習(xí)題來自于《劍指 Offer》第 29 題:數(shù)組中超過一半的數(shù)字,不知道各位去思考了么?

面試題:數(shù)組中有一個數(shù)字出現(xiàn)的次數(shù)超過數(shù)組長度的一半,請找出這個數(shù)字并輸出。比如 {1,2,3,2,2,2,1} 中 2 的次數(shù)是 4,數(shù)組長度為 7,所以輸出 2。要求不能修改輸入的數(shù)組。

準備測試用例

這道題能思考到的測試用例比較簡單。

  1. 輸入符合條件的數(shù)組,查看打印是否滿足情況;
  2. 輸入不符合條件的數(shù)組,查看打??;
  3. 輸入只有一個元素的數(shù)組,查看打??;
  4. 輸入無效數(shù)組,查看打??;

思考程序邏輯

第二步便是我們的思考程序邏輯了,題目要求查找出現(xiàn)次數(shù)超過一半的數(shù)字。比較容易想到的思路是直接對數(shù)組排序,那中間那個值就是我們想要的值,但這樣的想法明顯排序后會對輸入的數(shù)組順序有影響,所以我們可能需要換一種思路。

再看一遍題干,我們不難思考到,我們是否可以對每個數(shù)字進行計數(shù),最后返回計數(shù)次數(shù)最多的值。存儲次數(shù)采用 map 做映射處理。

public class Test19 {
    private static int moreThanHalfNums(int[] nums) {
        if (nums == null || nums.length == 0)
            throw new RuntimeException("the length of array must be large than 0");
        int len = nums.length;
        Map<Integer, Integer> map = new HashMap<>();

        for (int num : nums) {
            if (map.containsKey(num))
                map.put(num, map.get(num) + 1);
            else
                map.put(num, 1);
        }
        int times = len / 2;
        // 查找 map 中 value 最大的值
        for (Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > times)
                return entry.getKey();
        }
        throw new RuntimeException("invalid input!");
    }

    public static void main(String[] args) {
        int[] nums1 = {1, 2, 3, 2, 2, 4, 2, 2, 5};
        System.out.println(moreThanHalfNums(nums1));
        int[] nums2 = {1};
        System.out.println(moreThanHalfNums(nums2));
        int[] nums3 = {2, 1, 2, 1, 2, 2, 3, 2, 1};
        System.out.println(moreThanHalfNums(nums3));
        int[] nums4 = {1, 2, 3, 4, 5};
        System.out.println(moreThanHalfNums(nums4));
    }
}

寫畢后進行測試用例的驗證,無不例外,目前都通過,于是我們把這樣的代碼解法遞交給面試官。

面試官看了這樣的算法,表示他更期待的是不使用任何輔存空間的算法。于是我們得換個角度思考。

數(shù)組中有一個數(shù)字出現(xiàn)的次數(shù)超過數(shù)組長度的一半,也就是說它出現(xiàn)的次數(shù)比其他所有數(shù)字出現(xiàn)次數(shù)的和還要多。因此我們可以考慮在遍歷數(shù)組的時候保存兩個值: 一個是數(shù)組中的一個數(shù)字, 一個是次數(shù)。當(dāng)我們遍歷到下一個數(shù)字的時候,如果下一個數(shù)字和我們之前保存的數(shù)字相同,則次數(shù)加 1 ;如果下一個數(shù)字和我們之前保存的數(shù)不同,則次數(shù)減 1。如果次數(shù)為 0,我們需要保存下一個數(shù)字,并把次數(shù)設(shè)為 1 。由于我們要找的數(shù)字出現(xiàn)的次數(shù)比其他所有數(shù)字出現(xiàn)的次數(shù)之和還要多,那么要找的數(shù)字肯定是最后一次把次數(shù)設(shè)為 1 時對應(yīng)的數(shù)字。

我們來看這樣的思路用代碼怎么實現(xiàn)。

public class Test19 {

    private static int moreThanHalfNums(int[] nums) {
        if (nums == null || nums.length == 0)
            throw new RuntimeException("the length of array must be large than 0");
        int result = nums[0];
        int times = 1;
        int len = nums.length;
        for (int i = 1; i < len; i++) {
            if (times == 0) {
                result = nums[i];
                times = 1;
            } else if (result == nums[i])
                times++;
            else
                times--;
        }
        times = 0;
        for (int num : nums) {
            if (num == result)
                times++;
        }
        if (times > len / 2)
            return result;
        throw new RuntimeException("invalid input!");
    }

    public static void main(String[] args) {
        int[] nums1 = {1, 2, 3, 2, 2, 4, 2, 2, 5};
        System.out.println(moreThanHalfNums(nums1));
        int[] nums2 = {1};
        System.out.println(moreThanHalfNums(nums2));
        int[] nums3 = {2, 1, 2, 1, 2, 2, 3, 2, 1};
        System.out.println(moreThanHalfNums(nums3));
        int[] nums4 = {1, 2, 3, 4, 5};
        System.out.println(moreThanHalfNums(nums4));
    }
}

寫畢后,驗證測試用例,同樣全部通過。

本題最后的思路,希望大家刻意去思考和記憶一下,因為也許變一下題意,這樣的想法還可以用到。

課后習(xí)題

我們下一次推文的題目來源于《劍指 Offer》第 31 題:計算連續(xù)子數(shù)組的最大和。

面試題:輸入一個整型數(shù)組,數(shù)組中有正數(shù)也有負數(shù)。數(shù)組中一個或多個整數(shù)形成一個子數(shù)組,求所有子數(shù)組的和的最大值,要求時間復(fù)雜度為 O(n)。
比如輸入 {1, -2, 3, 10, -4, 7, 2, -5},能產(chǎn)生子數(shù)組最大和的子數(shù)組為 {3,10,-4,7,2},最大和為 18。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 數(shù)組 記錄《劍指offer》中所有關(guān)于數(shù)組的題目,以及LeetCode中的相似題目 相關(guān)題目列表 說明 由于簡書...
    wenmingxing閱讀 1,610評論 1 12
  • 說明: 本文中出現(xiàn)的所有算法題皆來自??途W(wǎng)-劍指Offer在線編程題,在此只是作為轉(zhuǎn)載和記錄,用于本人學(xué)習(xí)使用,不...
    秋意思寒閱讀 1,223評論 1 1
  • 面試 18:復(fù)雜鏈表的復(fù)制(劍指 Offer 第 26 題) 在上一篇推文中,我們留下的習(xí)題是來自《劍指 Offe...
    nanchen2251閱讀 612評論 0 5
  • 你真的連我生命中的過客都不算,我是喜歡你的,因為我是手控,而恰巧你的手很漂亮,以前從來不會相信因為一種行為或者是一...
    涼薄123閱讀 168評論 0 0
  • 前幾天和一個朋友聊天,關(guān)于孩子的教養(yǎng)問題,她說孩子大了越來越難養(yǎng)了,不知道該如何去管教了。正巧我寫了一篇有關(guān)于這方...
    娜小娜512閱讀 335評論 0 1

友情鏈接更多精彩內(nèi)容