【LeetCode】每日一題164. 最大間距

喜歡下雨所以愛上雷震子發表於2020-11-27

164. 最大間距

給定一個無序的陣列,找出陣列在排序之後,相鄰元素之間最大的差值。

如果陣列元素個數小於 2,則返回 0。

示例 1:

輸入: [3,6,9,1]
輸出: 3
解釋: 排序後的陣列是 [1,3,6,9], 其中相鄰元素 (3,6)(6,9) 之間都存在最大差值 3

示例 2:

輸入: [10]
輸出: 0
解釋: 陣列元素個數小於 2,因此返回 0

說明:

  • 你可以假設陣列中所有元素都是非負整數,且數值在 32 位有符號整數範圍內。
  • 請嘗試線上性時間複雜度和空間複雜度的條件下解決此問題。

解題思路:

此題難在如何用線性的時間複雜度(O(n))解決,否則直接快排歸併再取相鄰元素最大差值即可。

此題沒有必要保證元素的絕對有序,使用桶排序保證元素相對有序即可

大體思路:建立若干個桶,每個桶負責固定區間的元素,按照一定規則將元素放進桶中。

  1. 區間:section = (max - min ) / (n - 1) ,其中 max 為陣列最大值,min 為陣列最小值,n 為陣列長度 。

  2. 桶的數量: bucketSize = (max - min ) / section + 1。

  3. 一定規則: idx = (nums[i] - min) / section,idx 為桶的編號。

示例:

假設初始元素為(為了直觀所以排序了):[0,4,5,8,18,19,23,32,39],區間 section = (39 - 0) / (8 - 1) = 5,桶數量 bucketSize = (39 - 0) / 5 + 1 = 8

按照規則將元素放入桶中,如下圖:
在這裡插入圖片描述
再看一種極端情況:等差數列。顯而易見,最大的差值就是 section = 5,
在這裡插入圖片描述
若元素不為等差數列,最大的差值一定大於 section
所以最大的差值不會出現在桶內,因為單個桶內最大的差值小於 section
即最大的差值在桶與桶之間

我們維護每個桶的最大值與最小值,然後遍歷桶,找出之間最大的差值即可。

方法一:桶排序

int n = nums.length;
    // 特判
    if (n < 2) {
        return 0;
    }

    // 找出最大值,最小值
    int max = Arrays.stream(nums).max().getAsInt();
    int min = Arrays.stream(nums).min().getAsInt();
	
	// 所有數都相等
    if (max - min == 0){
        return 0;
    }

    // 計算桶區間
    int section = Math.max(1, (max - min) / (n - 1));
    // 桶的個數
    int bucketSize = (max - min) / section + 1;

    // 每個桶的最小值
    int[] min_bucket = new int[bucketSize];
    // 每個桶的最大值
    int[] max_bucket = new int[bucketSize];
    // 初始化桶
    Arrays.fill(min_bucket, Integer.MAX_VALUE);
    Arrays.fill(max_bucket, -1);

    for (int i = 0; i < n; i++) {
        // 確定當前值在哪個桶
        int idx = (nums[i] - min) / section;
        // 更新最大值和最小值
        min_bucket[idx] = Math.min(min_bucket[idx], nums[i]);
        max_bucket[idx] = Math.max(max_bucket[idx], nums[i]);
    }

    // 結果
    int  ret = 0;
    // 前一個桶的最大值
    int prevMax = -1;
    for (int i = 0; i < bucketSize; i++) {
        // 桶裡沒有元素
        if (max_bucket[i] == -1) {
            continue;
        }
        // 計算桶間的最大值
        if (prevMax != -1) {
            ret = Math.max(ret, min_bucket[i] - prevMax);
        }
        prevMax = max_bucket[i];
    }

    return ret;

執行結果:

在這裡插入圖片描述
說明:

桶排序的時間複雜度和空間複雜度都為O(n)。測試用例過少,所以效率不如直接排序再遍歷求解來得高。

相關文章