-
前言 :
想写些东西记录自己所学的收获。 -
先上题目 :
- 思路:
- 比较器
最简单的按排序之后再逐个遍历找出最大差值,但这显然不符合题目要求。 不过这个思路可以当成比较器来用,来检测之后写的代码是否是否要求。
public static int comparator(int[] nums) { if(nums == null || nums.length < 2) { return 0; } Arrays.sort(nums); int gap = Integer.MIN_VALUE; for(int i = 1; i < nums.length; i++) { gap = Math.max(nums[i]-nums[i-1], gap); } return gap; }
- 桶排序的思想。
假如有N个数,则需要N+1个桶。 这里桶的序号为0开始计数,当然也可以从1开始。 每个桶记录自己桶是否放进来过数字(boolean类型),记录自己桶的最大值和最小值。
先遍历一遍数组,找出最大值和最小值。如果最大最小值相等,则最大差值是0。 不相等在进行之后操作。 最大值(单独)放入最后一个桶(即第N个桶0),最小值放入最前面的那个桶(即第0个桶)。每个桶都装等区间的数,或者说每个装的 数的范围 是 (最大值-最小值)/ N。
在说说为什么要N+1个桶:
因为这样可以排除最大差值来自桶一个桶的情况。
因为N个数,放N+1个桶,必然最少有一个桶是空桶。那么最大差值就可能来自空桶的左右两侧桶的最值相减。(只是可能,但并不一定)。
比如下面这种情况:
-
上代码
public static int maxGap(int[] arr) {
if(arr == null || arr.length < 2) {
return 0;
}
// 只是给 最值 进行初始化,实际是想要数组中的数字
// 全局的最大最小值
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
int len = arr.length;
for(int i = 0; i < len; i++) {
max = Math.max(arr[i], max);
min = Math.min(arr[i], min);
}
if(max == min) {
return 0;
}
boolean bucketHasNum[] = new boolean[len+1]; // 每个桶是否装进来过数。缺省值全是 false
int bucketMax[] = new int[len+1]; // 每个桶当中的最大值
int bucketMin[] = new int[len+1]; // 每个桶当中的最小值
int bid = 0; // 第几号桶。 从0开始计数
for(int i = 0 ; i < len; i++) {
bid = bucket(arr[i], len, max, min);
bucketMax[bid] = bucketHasNum[bid] ? Math.max(arr[i], bucketMax[bid]) : arr[i];
bucketMin[bid] = bucketHasNum[bid] ? Math.min(arr[i], bucketMin[bid]) : arr[i];
bucketHasNum[bid] = true;
}
int res = 0; // 最大差值
int lastMax = bucketMax[0];
for(int i = 1 ; i <= len; i++) {
if(bucketHasNum[i]) {
res = Math.max(res, bucketMin[i] - lastMax); // 不能直接bucketMin【i】-bucketMax【i-1】,因为还有空桶
lastMax = bucketMax[i];
}
}
return res;
}
// 判断 一个数 要装入 第几号桶
public static int bucket(long num, long len, long max, long min) {
return (int)( (num-min) * len / (max-min) );
}
这块代码 bucket 这个功能耗了我基本一天的时间,搞不明白就很难受…
以下是我当下阶段的理解:
(图片中的最小值min为0)
这个数字 减去 最小值, 就是距最小值的距离。
第 i 号桶 乘 区间长度len 就是 代表这个桶中装入的数字范围。(因为是计算机中的除法。 )