劍指offer(二):不修改數組找出重複的數字

❝
成功呈概率分佈,關鍵是你能不能堅持到成功開始呈現的那一刻。—— 佚名

❞

不修改數組找出重複的數字


題目描述

在一個長度爲 n+1 的數組裏的所有數字都在 1 到 n 的範圍內,所以數組中至少有一個數字是重複的。請找出數組中任意一個重複的數字,但不能修改輸入的數組。例如,如果輸入長度爲 8 的數組 {2, 3, 5, 4, 3, 2, 6, 7},那麼對應的輸出是重複的數字 2 或者 3。

解法

解法一
創建長度爲 n+1 的輔助數組,把原數組的元素複製到輔助數組中。如果原數組被複制的數是 m,則放到輔助數組第 m 個位置。這樣很容易找出重複元素。空間複雜度爲 O(n)。

解法二
數組元素的取值範圍是 [1, n],對該範圍對半劃分,分成 [1, middle], [middle+1, n]。計算數組中有多少個(count)元素落在 [1, middle] 區間內,如果 count 大於 middle-1+1,那麼說明這個範圍內有重複元素,否則在另一個範圍內。繼續對這個範圍對半劃分,繼續統計區間內元素數量。

時間複雜度 O(n * log n),空間複雜度 O(1)。

注意,此方法無法找出所有重複的元素。

public class Solution {
    /**
     * 不修改數組查找重複的元素,沒有則返回-1
     * @param numbers 數組
     * @return 重複的元素
     */
    public int getDuplication(int[] numbers) {
        if (numbers == null || numbers.length < 1) {
            return -1;
        }

        int start = 1;
        int end = numbers.length - 1;
        while (end >= start) {
            int middle = start + ((end - start) >> 1);

            // 調用 log n 次
            int count = countRange(numbers, start, middle);
            if (start == end) {
                if (count > 1) {
                    return start;
                }
                break;
            } else {
                // 無法找出所有重複的數
                if (count > (middle - start) + 1) {
                    end = middle;
                } else {
                    start = middle + 1;
                }
            }
        }
        return -1;
    }

    /**
     * 計算整個數組中有多少個數的取值在[start, end] 之間
     * 時間複雜度 O(n)
     * @param numbers 數組
     * @param start 左邊界
     * @param end 右邊界
     * @return 數量
     */
    private int countRange(int[] numbers, int start, int end) {
        if (numbers == null) {
            return 0;
        }
        int count = 0;
        for(int e : numbers) {
            if (e >= start && e <= end) {
                ++count;
            }
        }
        return count;
    }
}

測試用例

  1. 長度爲 n 的數組中包含一個或多個重複的數字;
  2. 數組中不包含重複的數字;
  3. 無效測試輸入用例(輸入空指針)。

我把我寫的所有題解整理成了一本電子書放在了 github 上,三天內衝擊到 github 排行榜榜首!近 5w 人下載閱讀!要獲取的話,直接進入下方鏈接就可以了(記得給我點個 star):

https://github.com/geekxh/hello-algorithm

劍指offer(二):不修改數組找出重複的數字

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