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.
给出一个无序数组,求数组里的这些元素按排序情况下相邻元素相差的最大值。
比如{6,1,2},那么就是2、6之间相差最大,返回4
这道题最容易想到的就是把数组排好序,然后遍历一次,找到相差最大的两个相邻元素,事实上这么做也是可以通过的。
public int maximumGap(int[] nums) {
if(nums.length < 2){
return 0;
}
Set<Integer> set = new TreeSet<Integer>();
for(int i=0;i<nums.length;i++){
set.add(nums[i]);
}
int max = 0;
Iterator<Integer> it = set.iterator();
int before = it.next();
while(it.hasNext()){
int after = it.next();
max = Math.max(max, after - before);
before = after;
}
return max;
}
那么有没有O(n)的时间复杂度实现?还是有的,但是还是要往能做到O(n)时间的排序才能想到,像官方题解的桶排序就是如此,把属于同一区间的数放入同一个桶中。
用桶排序做此题的诀窍在于,划分桶的总数量、单个桶的容量时,要保证桶之间的差值一定大于桶内的差值,这样就只需要比较前一个桶里最大值与后一个桶最小值得差值即可。
public int maximumGap(int[] nums) {
if(nums.length < 2){
return 0;
}
int len = nums.length;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i=0;i<len;i++){
max = Math.max(max, nums[i]);
min = Math.min(min, nums[i]);
}
if(max - min < 2){
return max - min;
}
int aaaa = (int) Math.ceil((double)(max - min) / (len - 1));
int bucketCount = (max-min)/aaaa;
int M[] = new int[bucketCount+1];
int N[] = new int[bucketCount+1];
for(int i=0;i<bucketCount+1;i++){
M[i] = Integer.MIN_VALUE;
N[i] = Integer.MAX_VALUE;
}
for(int i=0;i<len;i++){
int index = (nums[i]-min) / aaaa;
M[index] = Math.max(M[index], nums[i]);
N[index] = Math.min(N[index], nums[i]);
}
if(bucketCount == 1){
return N[1] - M[0];
}
int result = 0;
int lastMax = Integer.MIN_VALUE;
if(M[0] != Integer.MIN_VALUE){
lastMax = M[0];
}
for(int i=1;i<M.length;i++){
if(N[i] != Integer.MAX_VALUE){
result = Math.max(N[i]-lastMax,result);
}
if(M[i] != Integer.MIN_VALUE){
lastMax = M[i];
}
}
return result;
}
另外还有一种解法是基数排序,基数排序从低位到高位对数组元素排序,最终能够达到完全排序的目的。
此种算法的时间复杂度依赖于待排序元素的最大位数i,复杂度为O(i*n),对于此题来说还是比较合适。
关键点在于如何把取余数相同后的元素放在同一区间,这里参考了leetcode的官方解答。
public int maximumGap(int[] nums) {
if(nums.length < 2){
return 0;
}
int len = nums.length;
int exp = 1;
int radix = 10;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i=0;i<len;i++){
max = Math.max(max, nums[i]);
min = Math.min(min, nums[i]);
}
while(max/exp>0){
int count[] = new int[radix];
for(int i=0;i<len;i++){
count[nums[i]/exp%10]++; //计算每个相同数字结尾的有多少个
}
for(int i=1;i<radix;i++){
count[i] += count[i-1]; //计算每个相同数字结尾的区间
}
int temp[] = new int[len];
for(int i=len-1;i>=0;i--){//把不同数字结尾的放入各自区间
temp[--count[nums[i]/exp%10]] = nums[i];
}
for(int i=len-1;i>=0;i--){
nums[i] = temp[i];
}
exp *= 10;
}
int result = nums[1] - nums[0];
for(int i=1;i<len;i++){
result = Math.max(result, nums[i] - nums[i-1]);
}
return result;
}
执行testcae 7ms的效率还是可以的,毕竟是完全排序,实现起来也比较容易理解。