请设计一个复杂度为O(n)的算法,计算一个未排序数组中排序后相邻元素的最大差值。
给定一个整数数组A和数组的大小n,请返回最大差值。保证数组元素个数大于等于2小于等于500。
测试样例:
[9,3,1,10],4
返回:6
由于除了桶排序外任何排序时间复杂最度低也是O(N*log2)所以我们考虑使用桶排序的思想
len 代表数组中数的个数
len个数 len+1个桶去装
最少也要有一个空桶(4个数去装5个桶 咋装满?)
根据以上条件装桶后
任何两个非空桶之间
左边桶最大的值和右边桶最小的值。。。。他们在正常排序后一定也是相邻的(好好体会这句话)
//由于一定会有空桶的存在,所以隔一个空桶之间的差值一定比自己桶内所有数的最大差值要大所以求最大差值我们不考虑桶内的数
//比如 3-4桶 最大值是3 9-10桶最小值是 9 他们中间隔了两个桶(任何情况都会最低有一个空桶存在)他们中间相隔的数就已经大大超过了
//自己桶内可能出现的差值
上代码
import java.util.*;
public class Main {
// 题目:
// 给定一个整形数组arr,返回排序后的相邻两数的最大差值。
// 时间复杂度为O(N)。
public static void main(String[] args){
//时间复杂度的限制让我们不可以排序
//已知任何排序的时间复杂度都可能是O(N)
//但是我们可以利用桶排序
//比如有arr.length 9个数 我们给他10个桶
//用我9个数的最大值和最小值 给他们划分10个等价空间
int[] arr = {0,-1,-2,3,-4,5,-6,7,-8};
int max = MaxGap(arr);
System.out.println(max);
}
public static int MaxGap(int[] arr){
if(arr.length<2||arr==null){
return 0;
}
int len =arr.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
//找出最大值和最小值
for(int i=0;i<len;i++){
min = Math.min(min,arr[i]);
max = Math.max(max,arr[i]);
}
//如果所有的值都相等
if(min==max){
return 0;
}
//准备3个动态数组
//分别,判断空桶、桶中的最小值、桶中最大值
boolean[] hasNum = new boolean[len+1];
int[] mins = new int[len+1];
int[] maxs = new int[len+1];
//桶的序号
int bid=0;
for(int i=0;i<len;i++){
//计算该数应该放在桶的下标
bid = bucket(arr[i],len,min,max);
mins[bid] = hasNum[bid]?Math.min(mins[bid],arr[i]):arr[i];
maxs[bid] = hasNum[bid]?Math.max(maxs[bid],arr[i]):arr[i];
hasNum[bid]=true;
}
//之所以用这种差值判断方式是为了防止空桶的存在
int res= 0;
int lastMax=maxs[0];
for(int i=1;i<=len;i++){
if(hasNum[i]){
res = Math.max(res,mins[i]-lastMax);
lastMax = maxs[i];
}
}
return res;
}
//计算该数应该放在桶的下标
public static int backet(long num,long len,long min,long max){
return (int)((num-min)*len/(max-min));
}
}