164. Maximum Gap
一、题目
1、审题
2、分析
给出一个无序的整形数组,求其有序时相邻元素的最大差值为多大。
二、解答
1、思路:
方法一、
桶排序。
①、首先找出数组中最大元素、最小元素: max 、min;
②、去除 max、min 时数组剩下 N - 2 个元素,取 N - 1 个桶进行存放,则一个桶内存放元素范围为: ceiling[(max - min ) / (N - 1)] ;且第 k 个桶存放的数值大小范围为 [min+ (k-1)gap, min+ k*gap);
③、可知至少有一个桶为空着的,所以相邻元素的最大差值必定在不同的桶之间,也即在前一个有效桶(非空)的最大值与后一个有效桶(非空)的最小值的差。
public int maximumGap2(int[] nums) { if(nums == null || nums.length < 2) return 0; int len = nums.length; int maxVal = Integer.MIN_VALUE; int minVal = Integer.MAX_VALUE; for (int i = 0; i < len; i++) { maxVal = Math.max(maxVal, nums[i]); minVal = Math.min(minVal, nums[i]); } // 取 len - 1 个桶时(去除 maxVal、minVal 后剩下 len - 2个数,必有一个空桶), 求解桶间最小的差值,向上取整 int gap = (int) Math.ceil((double)(maxVal - minVal)/(len - 1)); int[] maxBuk = new int[len - 1]; int[] minBuk = new int[len - 1]; Arrays.fill(maxBuk, Integer.MIN_VALUE); Arrays.fill(minBuk, Integer.MAX_VALUE); // 桶映射 for(int val: nums) { if(val == minVal || val == maxVal) continue; int idx = (val - minVal) / gap; maxBuk[idx] = Math.max(maxBuk[idx], val); minBuk[idx] = Math.min(minBuk[idx], val); } //求解最大gap,最大差值位于后桶的min-前桶的max int maxGap = Integer.MIN_VALUE; int pre = minVal; for (int i = 0; i < len - 1; i++) { if(maxBuk[i] == Integer.MIN_VALUE && minBuk[i] == Integer.MAX_VALUE) continue; maxGap = Math.max(maxGap, minBuk[i] - pre); pre = maxBuk[i]; } maxGap = Math.max(maxGap, maxVal - pre); return maxGap; }
方法二、
基数排序
动画演示:https://www.cs.usfca.edu/~galles/visualization/RadixSort.html
①、找出数组最大值,用于控制循环;
②、运用技术排序,从最低位到最高位进行排序;
③、 (nums[i] / exp) % 10 用于获取数字排序的数值, 且数字本身就是访问 count 数组的索引 ;
count 数组存储访问 AUX 的索引,根据 Aux 当前的顺序存储排序后的数字。
public int maximumGap3(int[] nums) { if(nums == null || nums.length < 2) return 0; int max = nums[0]; for (int i = 1; i < nums.length; i++) max = Math.max(max, nums[i]); int exp = 1; // 1, 10, 100, 1000 int R = 10; int[] aux = new int[nums.length]; while(max / exp > 0) { // Go through all digits from LSB to MSB int[] count = new int[R]; for (int i = 0; i < nums.length; i++) count[(nums[i] / exp) % 10]++; for (int i = 1; i < count.length; i++) count[i] += count[i - 1]; for (int i = nums.length - 1; i >= 0; i--) aux[--count[(nums[i] / exp) % 10]] = nums[i]; for (int i = 0; i < nums.length; i++) nums[i] = aux[i]; exp *= 10; } max = 0; for (int i = 1; i < aux.length; i++) max = Math.max(max, aux[i] - aux[i - 1]); return max; }