引言
无限长的无序数组 ,正负零都有可能。求出排序后最大的相邻的差值 时间复杂度O(N) 且要求不能用非基于比较的排序
思路
1. 找出数组中的最大元素,分配最大元素+1个桶,对桶等分如一号桶(0-9)、二号桶(10-19).....
2. 因为元素最大是N,所以准备了N+1个桶,所以肯定最小桶和最大桶肯定有数,中间有空桶
3. 如果两个非空桶中间有空桶,那么排序后前一个非空桶最大值,肯定小于后一个非空桶最小值。肯定是相邻的。中间是空桶。
例如: 非空桶(0-9) 、空桶(10-19)、非空桶(20-29) 如果第一个非空桶最大值是9,第二个非空桶最小值是20,那么必然成 后一个非空桶最小值大于前一个非空桶最大值。而且排序后元素9后面必然是元素20.中间是空桶,没有元素、
4. 后一个非空桶的最小值减去前一个非空桶的最大值,必然大于等于桶的取值范围。
例如:非空桶(0-9) 、空桶(10-19)、非空桶(20-29) 那么前一个非空桶最小值范围是(0-9).第二个非空桶最小值是(20-29), 那么,最大值范围-最小值范围(最小元素9 最大元素20 差值11 最小是0 最大是20 差值20)必然大于等于空桶(10-19)的范围。
5. 因为第四步,可以知道,不用计算桶内相减的范围。直接计算后一个桶最小值减去前一个桶最大值来得到差值,那么桶只用记录负责范围上最小值和最大值是多少。
6. 计算的差值进行比较,得到最后最大差值。因为两个非空桶中间有个空桶。后一个非空桶最小值减去前一个非空桶最大值的得到的差值不一定是排序后最大差值,所以差值需要进行比较。
代码
public class MaximumDifference {
public static long maximumDifference(int[] arr){
if(null == arr || arr.length <2) {
return 0;
}
int len = arr.length;
//设置最小和最大系统值,最小值是系统最大值,最大值是系统最小值
long max = Long.MIN_VALUE;
long min = Long.MAX_VALUE;
// 计算最大值最小值
for (int i = 0; i < len; i++){
max = Math.max(max,arr[i]);
min = Math.min(min,arr[i]);
}
// 最大值等于最小值
if(max == min) {
return 0;
}
// 创建桶
// 判断桶是否添加过数字
boolean[] hasNum = new boolean[len + 1];
// 存储桶最小值
int[] minNum = new int[len + 1];
// 存储桶最大值
int[] maxNum = new int[len + 1];
// 桶号
int bid = 0;
for (int i=0;i<len;i++){
//分配桶的区域 哪个数进入哪个桶
bid = bucket(arr[i], len, min, max);
minNum[bid] = hasNum[bid]? Math.min(minNum[bid], arr[i]) : arr[i];
maxNum[bid] = hasNum[bid]? Math.max(maxNum[bid], arr[i]) : arr[i];
hasNum[bid] = true;
}
//最大差值
int res = 0;
// 从零号桶开始 零号桶必定有值
int lastMax = maxNum[0];
// 循环遍历非空桶 计算差值
for(int i = 1; i<=len; i++) {
if(hasNum[i]) {
// 判断哪个差值最大
res = Math.max(res, minNum[i] - lastMax);
// 继续进行最大值最小值遍历
lastMax = maxNum[i];
}
}
return res;
}
/**
* 计算在桶的位置
* @param num 当前数
* @param len 桶个数
* @param min 最小值
* @param max 最大值
* @return
*/
public static int bucket(long num, long len, long min, long max){
return (int) ((num - min) * len / (max - min));
}
}
利用桶的原理,来进行找到相邻最大差值,时间复杂度O(N);