[LeetCode] 164. Maximum Gap
Given an unsorted array, find the maximum difference between the successive elements in its sorted form.
Return 0 if the array contains less than 2 elements.
Example 1:
Input: [3,6,9,1] Output: 3 Explanation: The sorted form of the array is [1,3,6,9], either (3,6) or (6,9) has the maximum difference 3.
Example 2:
Input: [10] Output: 0 Explanation: The array contains less than 2 elements, therefore return 0.
Note:
- You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.
- Try to solve it in linear time/space.
最大间距。
题意是给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。如果数组元素个数小于 2,则返回 0。
这道题由于要求是在线性时间和空间内解决,所以思路是桶排序。桶排序的具体做法如下,这里的桶排序跟其他题目涉及到的桶排序/计数排序是不同的,这里我们是试图要把元素放入每一个桶但是又想确保有一个bucket是空的。这个空的bucket的前一个bucket里的最大值和后一个bucket里的最小值的差值就是要求的最大差值。比如我们有 N 个元素,我们可以试图给 N + 1 个bucket,那么一定有一个bucket是空的。这个推论类似于抽屉原理。我们可以找这个空的bucket的左右两个邻居bucket来得到这个最大差值。
所以具体的做法是,遍历input数组,得到数组中的最大值max和最小值min,此时我们可以得到桶的size = (int) Math.ceil((double) (max - min) / (len - 1))。这个公式我暂时不知道怎么推导,暂且当做结论记住。同时我们还需要两个长度为 len - 1 的数组来分别记录每个bucket里的最大值和最小值。
再次遍历input数组,如果遇到min和max就跳过,因为他们是第一个bucket的最小值和最后一个bucket的最大值,第一个bucket左边没有bucket,最后一个bucket的右边也没有bucket,所以他们没有办法参与到res的计算中,可以跳过。桶的size得到之后,对于每一个元素,我们通过这个公式就知道应该把他放入哪个bucket了。放入之后同时记得更新这个桶内的最大值和最小值。
int bucket = (num - min) / gap;
最后遍历桶的最大值数组和最小值数组,记得单独处理min和第一个桶子里的最小值的差值以及max和最后一个桶子里的最大值的差值计算。
时间O(n) - required
空间O(n)
Java实现
1 class Solution { 2 public int maximumGap(int[] nums) { 3 // corner case 4 if (nums == null || nums.length < 2) { 5 return 0; 6 } 7 // normal case 8 int len = nums.length; 9 int min = nums[0]; 10 int max = nums[0]; 11 for (int num : nums) { 12 min = Math.min(min, num); 13 max = Math.max(max, num); 14 } 15 // bucket size 16 int gap = (int) Math.ceil((double) (max - min) / (len - 1)); 17 int[] bucketMin = new int[len - 1]; 18 int[] bucketMax = new int[len - 1]; 19 Arrays.fill(bucketMin, Integer.MAX_VALUE); 20 Arrays.fill(bucketMax, Integer.MIN_VALUE); 21 for (int num : nums) { 22 // 跳过最大值和最小值是因为最大值是最后一个bucket的上限,他的右边没有bucket了 23 // 最小值是第一个bucket的下限,他的左边没有bucket了 24 // 所以实际是没法参与到res的计算中的,所以直接就不放了 25 if (num == min || num == max) { 26 continue; 27 } 28 int bucket = (num - min) / gap; 29 bucketMin[bucket] = Math.min(num, bucketMin[bucket]); 30 bucketMax[bucket] = Math.max(num, bucketMax[bucket]); 31 } 32 33 int res = 0; 34 int pre = min; 35 for (int i = 0; i < len - 1; i++) { 36 if (bucketMin[i] == Integer.MAX_VALUE && bucketMax[i] == Integer.MIN_VALUE) { 37 continue; 38 } 39 res = Math.max(res, bucketMin[i] - pre); 40 pre = bucketMax[i]; 41 } 42 res = Math.max(res, max - pre); 43 return res; 44 } 45 }