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,我發現桶排序做出來好像比基數排序慢也。