题目要求:
给定一个无序的数组,求该数组排好序后的相邻两个数的最大差值,要求时间复杂度为O(n),且不能使用非基于比较的排序,比如:3,1,6,2,7 ,排序序之后是,1,2,3,6,7。两个数的最大差值是 3。
代码实现与分析:
这个问题实现思路非常的器巧妙,借用了桶的概念,但是没有进行桶排序。
package com.isea.brush;
/**
* 求相邻两个数的最大差值
* 实现思路:N个数,先遍历一遍数组,找到最大值和最小值,然后将该数组分成 N + 1(0~N)个桶,那么必定至少存在一个空桶;
* 然后将max - min 范围内的数分成 N + 1 份,放置到各个桶中,最小值在第一个桶,最大值在最后一个桶中,最大差值一定不在
* 同一个桶中,
*/
public class MaxGap {
public static int maxGap(int[] arr){
if (arr == null || arr.length < 2){
return 0;
}
int length = arr.length;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < length; i++) {
max = Math.max(max,arr[i]);
min = Math.min(min,arr[i]);
}
// 如果数组中只有一个数
if (max == min){
return 0;
}
boolean[] hasNum = new boolean[length + 1];
int[] maxs = new int[length + 1];
int[] mins = new int[length + 1];
int bid = 0;// 表示数组中的当前元素应该进入哪个桶(打标记)
// 更新桶中的最大值和最小值和是否进入过数
for (int i = 0; i < length; i++) {
bid = bucket(arr[i],length,min,max);
mins[bid] = hasNum[bid] ? Math.min(arr[i],mins[bid]) : arr[i];
maxs[bid] = hasNum[bid] ? Math.min(arr[i],maxs[bid]) : arr[i];
hasNum[bid] = true;
}
// 遍历每一个桶,比较当前非空桶的最小值和上一个非空桶的最大值之间的差值和全局差值的大小关系
int result = 0;
int lastMax = maxs[0];
for (int i = 1; i < maxs.length; i++) {
if (hasNum[i]){
result = Math.max(result, mins[i] - lastMax);
lastMax = maxs[i];
}
}
return result;
}
/**
* 确定num的桶编号
* @param num
* @param length
* @param min
* @param max
* @return
*/
private static int bucket(int num, int length, int min, int max) {
return((num - min) * length / (max - min));
}
}