1. 程式人生 > >LeetCode 筆記28 Maximum Gap

LeetCode 筆記28 Maximum Gap

Given an unsorted array, find the maximum difference between the successive elements in its sorted form.

Try to solve it in linear time/space.

Return 0 if the array contains less than 2 elements.

You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.

這道題題目有提示。

提示1 有線性時間複雜度解法

提示2 非負數,且強調32位整數

首先想排序的話,線性時間複雜度就那麼幾個解法,點陣圖和基數排序。顯然這個不能用點陣圖,空間消耗太大。其實在看Algorithm 4th edition的時候就想,基數排序真是強大,完全可以用來做這個麼。

不過當時我忘記基數排序的counting方法了。複習了一下才記起來。

public int maximumGap(int[] num) {
        if (num == null || num.length <= 1) {
            return 0;
        }

        
for (int d = 0; d < 32; d++) { int[] count = new int[3]; int[] aux = new int[num.length]; for (int i = 0; i < num.length; i++) { count[((num[i] >> d) & 1) + 1]++; } for (int i = 1; i < 2; i++) { count[i]
+= count[i - 1]; } for (int i = 0; i < num.length; i++) { aux[count[((num[i] >> d) & 1)]++] = num[i]; } for (int i = 0; i < num.length; i++) { num[i] = aux[i]; } } int maxGap = 0; for (int i = 1; i < num.length; i++) { if (num[i] - num[i - 1] > maxGap) { maxGap = num[i] - num[i - 1]; } } return maxGap; }

count陣列的意義具體可以參考上面提到的書關於String Sort的第一部分。

然後看了下leetcode的標準答案,原來用的桶排序。這個也很強大。

假設陣列中最大元素是Max, 最小元素Min,陣列的長度是len,那麼相鄰兩個數的平均間隔是D = (Max - Min)/(len - 1)。相鄰兩個數的最大間隔肯定大於等於這個數值。

那麼我們不妨假設[Min, Max]之間所有數都可以放在緊緊排列的一個個桶中。每個桶的大小就是D。桶內元素是之間的間隔肯定不是要求的最大間隔,而是前一個桶中的最大值和後面一個桶的最小值才可能是最大間隔。我們遍歷這樣的值,就可以找出最大間隔。

桶的個數麼,就是(Max - Min) / D + 1。

值為K的元素呢,就屬於第(K - Min) / D 個桶裡面了。

我們遍歷一次陣列,把每個桶都填上陣列中的元素,同時可以求得每個桶的最大最小值。

再遍歷一次桶,就求得了那個最大的間隔。

最後注意,如果len算出來是0,那麼桶的個數就等於元素個數。

public int maximumGap2(int[] num) {
        if (num == null || num.length <= 1) {
            return 0;
        }
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < num.length; i++) {
            if (num[i] > max) {
                max = num[i];
            }
            if (num[i] < min) {
                min = num[i];
            }
        }
        int len = (max - min) / (num.length - 1);
        if (len == 0) {
            len = 1;
        }
        int numOfBucket = (max - min) / len + 1;
        Bucket[] buckets = new Bucket[numOfBucket];
        for (int i = 0; i < num.length; i++) {
            int idx = (num[i] - min) / len;
            if (buckets[idx] == null) {
                buckets[idx] = new Bucket();
            }
            if (num[i] > buckets[idx].max) {
                buckets[idx].max = num[i];
            }
            if (num[i] < buckets[idx].min) {
                buckets[idx].min = num[i];
            }
        }
        int maxGap = 0;
        max = -1;
        for (int i = 0; i < buckets.length; i++) {
            if (buckets[i] != null) {
                if (max == -1) {
                    //pass
                } else {
                    maxGap = Math.max(buckets[i].min - max, maxGap);
                }
                max = buckets[i].max;
            }
        }
        return maxGap;
    }

However,我發現桶排序做出來好像比基數排序慢也。