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.
思路分析:这题要求O(N)的时间和空间复杂度,显然不能使用quick sort,merge sort, heap sort这类基于比较的排序算法,因为是O(Nlog(N))的时间复杂度。于是我们考虑使用bukit sort,radix sort,counting sort的思路。这里给出基于bukit sort的解法。假设num数组中最大值和最小值为max和min,那么我们可以令每个桶的大小为bukitLength = Math.ceil((double) (max - min) / (double) (n-1)),我们定义(max - min) / bukitLength + 1个桶,就可以保证存下从min到max这个range内的所有值。注意其实我们也可以定义其他的桶大小,比如Math.ceil((double) (max - min) / (double) (n)), 但此时要注意防止出现最大元素的桶index越界的情况,我们可以多定义一个bukit。定义好桶之后,就可以根据元素大小放入桶中。注意max gap不可能存在于同一个桶的元素之间,因为同一个桶的元素之间个gap至多只能是bukitLength-1,如果max gap是某两个同一个桶中的元素,那么这些数的range一定比max - min要小,出现矛盾。所以,对于数组中的任意整数K,可以通过算式loc = (K - min) / bukitLength找出其桶的位置,然后维护每一个桶的最大值和最小值。对于每一个非空的桶p,找出下一个非空的桶q,则q.min - p.max可能就是备选答案。返回这些备选答案中最大的一个即可。在实现的过程中犯了一个不该犯的错误,没有注释掉测试输出语句,导致超时。输出语句显然是很费时的,以后要引以为戒。
AC Code
public class Solution {
public int maximumGap(int[] num) {
if(num == null || num.length < 2) return 0;
int n = num.length;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i = 0; i < n; i++){
max = Math.max(max, num[i]);
min = Math.min(min, num[i]);
}
int range = max - min;
int bukitLength = (int)Math.ceil((double) range / (double) (n-1));
int bukitNum = range / bukitLength + 1;
//System.out.println("BukitLength and BukitNum " + bukitLength + " " + bukitNum);
ArrayList<Integer> bukitMax = new ArrayList<Integer>();
ArrayList<Integer> bukitMin = new ArrayList<Integer>();
for(int i = 0; i < bukitNum; i++){
bukitMax.add(Integer.MIN_VALUE);
bukitMin.add(Integer.MAX_VALUE);
}
for(int i = 0; i < n; i++){
int bukitIndex = (num[i] - min) / bukitLength;
//if(bukitIndex == n) bukitIndex--; // use n-1 bukits could solve the index problem of the largest number
//System.out.println("i and bukitIndex: " + i + " " + bukitIndex);
//Just store the largest and minimum number;
bukitMax.set(bukitIndex, Math.max(num[i], bukitMax.get(bukitIndex)));
bukitMin.set(bukitIndex, Math.min(num[i], bukitMin.get(bukitIndex)));
}
int beforeMax = min;
int maxGap = Integer.MIN_VALUE;
for(int i = 0; i < bukitNum; i++){
if(bukitMax.get(i) == Integer.MIN_VALUE || bukitMin.get(i) == Integer.MAX_VALUE){//empty bukit
continue;
}
maxGap = Math.max(maxGap, bukitMin.get(i) - beforeMax);
beforeMax = bukitMax.get(i);
}
return maxGap;
}
}