高频面试题:
比如:3 1 6 2 7
排序后是:
这道题目借用了桶这个概念,但是没有进行桶排序
N个数准备N+1个桶
中间的数字:把min到max范围等分成N+1份,一个数属于哪号范围,就放到哪个桶里
例如:
排序之后的相邻数字可能在同一个桶,也可能在相邻的桶
15的相邻值,可能来自于11(同一个桶),可能来自于21(相邻桶)
N个数,准备N+1个桶,min放进第0个桶,max放进第N个桶,中间必有一个空桶
空桶左边非空桶的max值,与空桶右边非空桶的min值相邻,且min–max一定大于每个桶所表示的范围【比如一个桶表示10~19,那桶表示的范围是10,这两个值相减一定大于10】
所以在寻找最大差值的时候,不需要考虑同一个桶中的数据,最大差值一定来自于不同桶(前一个桶的max和后一个桶的min)
每个桶不需要统计桶中的所有数,只需要统计桶中的min和max;当然还需要统计一个boolean类型的数据,这个桶里是否为空
(1) 有数字进入某个桶,桶的boolean类型的变量就要从false变为true
(2) 如果是第一次进入桶,那min = max = 这个数
(3) 如果某个数字再次进入了某个桶,就更新这个桶中的min 和max
(4) 然后从1号桶开始(因为0号桶一定非空),如果是空的,跳到下一个桶,如果是非空的,找前一个非空桶。对于每一个非空桶,都找它前一个非空桶的max和当前这个桶的min
(5) min–max记录最大差值
(6) 要求的最大差值一定在其中是最大的,用一个全局变量就可以找到它
提问:为什么不是找那个空桶,计算空桶两侧的非空桶的min–max
答:如下面的情况,最大差值是19;我们提出这个空桶的概念是否定最大差值来自同一个桶
每个桶的三种信息(是否为空、min、max)用三个数组来描述
import java.util.Arrays; public class MaxGap { public static void main(String[] args) { int[] arr ={0,2,15,23,21,67,88,4,99};//答案44 // int[] arr ={1,2,3,6,7};//答案3 System.out.println(maxGap(arr)); } public static int maxGap(int[] arr){ if (arr.length<2 || arr == null) { return 0; } //1.遍历找到数组中的最小值min最大值max int min = arr[0]; int max = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i]<min) { min = arr[i]; } if (arr[i]>max) { max = arr[i]; } } System.out.println("min = "+min+" max = "+max); //2.如果数组中是一串相同的数字,差值为0 if (max == min) { return 0; } //3.构造3个桶 int len = arr.length; boolean[] hasNum = new boolean[len+1];//数组中的默认值是false int[] mins = new int[len+1]; int[] maxs = new int[len+1]; //4.重新遍历这个数组,找到每个桶中的max、min for (int i = 0; i < arr.length; i++) { //看数组中的每一个数字属于几号桶 int bucketNumber = bucket(arr[i], max, min, len); System.out.println("第"+i+"个数字在第"+bucketNumber+"号桶"); //桶中无数据 if (!hasNum[bucketNumber]) { mins[bucketNumber] = arr[i]; maxs[bucketNumber] = arr[i]; hasNum[bucketNumber] = true; }else {//桶中有数据 mins[bucketNumber] = Math.min(arr[i], mins[bucketNumber]); maxs[bucketNumber] = Math.max(arr[i], maxs[bucketNumber]); } } System.out.println("每个桶中的最小值mins"+Arrays.toString(mins)); System.out.println("每个桶中的最大值maxs"+Arrays.toString(maxs)); System.out.println(Arrays.toString(hasNum)); //找当前桶的min和前一个非空桶的max int maxGap = 0; int lastMax = maxs[0];//前一个非空桶的max for(int i=1; i<hasNum.length; i++){ if (hasNum[i]) { maxGap = Math.max((mins[i] - lastMax), maxGap); System.out.println("第"+i+"次最大值为 "+ maxGap); // if (lastMax - mins[i] > maxGap) { // maxGap = lastMax - mins[i]; // } lastMax = maxs[i]; } } return maxGap; } /** * 判断一个数字属于几号桶 * @param num 被判断的数字 * @param max 数组中的最大值 * @param min 数组中的最小值 * @param n 数组中的数据量N */ public static int bucket(int num, int max, int min,int n){ return (int)(num-min)*(n+1)/(max-min+1); } }