例题1
给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度为O(N),且要求不能用非基于比较的排序。
(1)准备桶,如果一个数组中有N个数,就准备N+1个桶,先遍历整个数组找到最小值和最大值,如果最小值和最大值相等,说明整个数组就只有一种数,最大差值是0。如果最小值和最大值不等,我们将最小值放在第0号桶里,最大值放在N号桶里。将(max-min)这个范围等分成N+1份,那么中间必定存在一个空桶,一个数属于哪个范围就放在哪个桶里。比如一个数组有9个数, 准备10个桶,假设数组中最小值是0,最大值是9,那么0就放在0号桶,9放在9号桶,中间的数放在中间的桶。相邻两数可能来自同一个桶,也可能来自相邻的桶,最大差值一定不来自相同桶的数。最大差值是来自:后一个桶的最小值和前一个桶的最大值之间的 ,那么差值一定是来自这里面的差值。桶只用来记录进入到桶的最大值和最小值。最大差值不一定是空桶两侧来自非空桶的情况。
package com.cisco.www.sort; 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]); } //如果最小值和最大值相等,那么久返回0,最大差值是0. if(min==max){ return 0; } //设计这三个数组,是为了记录出三个桶是否有值,最大值,最小值 boolean[] hasNum = new boolean[len+1]; int[] maxs = new int[len+1]; int[] mins = new int[len+1]; int bid = 0 ; for(int i= 0 ;i<len;i++){ //确定当前数去几号桶 bid = bucket(nums[i],len,min,max); 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]; int i= 1; for(;i<len;i++){ if(hasNum[i]) { res = Math.max(res, mins[i] - lastMax); lastMax = maxs[i]; } } return res; } private static int bucket(int num, int len, int min, int max) { return (int)((num-min)*len/(max-min)); } }