6.桶排序 计数排序 基数排序
桶排序,计数排序,基数排序
-
非基于比较的排序, 与被排序样本的实际数据状况很有关系, 所以实际中并不常使用, 思路也是挺简单的所以这里就不多讲了. -
时间复杂度与空间复杂度都为 -
稳定
重点题目
给定一个数组, 求排序之后,相邻两数的最大差值,要求时间复杂度为 , 且要求不能用非比较的排序.
-
例如, [3, 1, 6, 2, 7]排序后[1, 2, 3, 6, 7], 返回相邻元素的最大差值3.
思路:数组中有n个数, 我们准备n + 1个空桶, 遍历一遍数组, 将最小值放在0号桶里和最大值放在n号桶里. 其他的数怎么放呢? 把最小值与最大值等分成 n + 1份, 一个数属于哪个范围就放在哪个桶里.
-
举个例子: 假设最小值为0, 最大值为99. 数组中总共有9个数. 0~9进入0号桶, 10~19进1号桶, ... , 90~99进9号桶.
为什么要这么做?
我们知道至少一定剩下一个空桶, 这个空桶的左边非空桶的最大值与右边的非空桶的最小值一定是相邻的元素, 那么这两个元素之差一定大于桶内元素的之差. 所以这样是为了否定相邻两数的最大差值不在同一个桶中. 所以相邻两数的最大差值一定在相邻两个非空桶之间的两个数的差值.
为什么不找空桶两边的两个非空桶呢?
看下面的图所以一定要记住, 设计空桶的目的是为了否定相邻两数的最大差值不在同一个桶中.
public class MaxGap {
public static int maxGap(int[] nums){
if (nums == null || nums.length < 2)
return 0;
int len = nums.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < len; i++) {
min = Math.min(min, nums[i]);
max = Math.max(max, nums[i]);
}
if (min == max)
return 0;
/*
hasNum记录各个桶中是否有数据
maxs与mins记录各个桶中的最小值与最大值
*/
boolean[] hasNum = new boolean[len + 1];
int[] maxs = new int[len + 1];
int[] mins = new int[len + 1];
/*
下面的循环是为了, 将hasNum, maxs, mins填好
*/
int bid = 0;
for (int i = 0; i < len; i++) {
bid = bucket(nums[i], len, min, max); // nums[i] 这个数应该在哪个桶中?
mins[bid] = hasNum[bid] ? Math.min(mins[bid], nums[i]) : nums[i];
maxs[bid] = hasNum[bid] ? Math.max(maxs[bid], nums[i]) : nums[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;
}
/*
判断数num是属于哪一个桶
*/
public static int bucket(long num, long len, long min, long max){
return (int) ((num - min) * len / (max - min));
}
}