题目
有一个无序整型数组,如何求出该数组排序后的任意两个相邻元素的最大差值?要求时间和空间复杂度尽可能低。
思路
解法1:
使用任意一种时间复杂度为O(nlogn)
的排序算法(如快速排序),给原数组排序,然后遍历排序号的数组,并对每队相邻元素求差,最终得到最大差值。该解法的时间复杂度是O(nlogn)
,在不改变原数组的情况下,空间复杂度是O(n)
。
解法2:
- 1.利用计数排序的思想,先求出原数组的最大值max和最小值min的区间长度
k(k=max-min+1)
,以及偏移量d=min。 - 2.创建一个长度为k的新数组Array。
- 3.遍历原数组,每遍历一个元素,就把新数组Array对应下标的值+1。Array[n-min]的值+1。遍历结束后,Array的一部分元素值变成了1或更高的数值,一部分元素值仍然是0。
- 4.遍历新数组Array,统计出Array中最大的连续出现的0值得次数+1,即为相邻元素最大差值。
- 5.这条思路有限制,因为计数排序,只适用于正整数的排序。
解法3:
- 1.利用桶排序的思想,根据原数组的长度n,创建出n+1个桶,注意是n+1桶,每一个桶代表一个区间范围。其中第1个桶从原数组的最小值min开始,区间跨度是
(max -min)/n
。 - 2.遍历原数组,把原数组每一个元素插入到对应的桶中,记录每一个桶的最大值和最小值。
- 3.遍历所有的桶,,统计出每一个桶的最大值,和该桶右侧非空桶的最小值的差,数值最大的差即为原数组排序后的相邻最大差值。
注意,这里少了一个说明,为什么排序后最大的两个相邻元素的差,一定会是每一个桶的最大值,和该桶右侧非空桶的最小值的差,的最大值。
先从n个数,分到n+1个桶里,开始说明。第n+1个桶的区间,是[max,max],第1个桶的区间,是[min,min+d],d为前n个桶区间的差值。n个数,最小值,一定落在第一个桶里,最大值,一定在n+1个桶里,还有n-2个数,n-2个数,分散到n+1-2=n-1个桶里,则在这n-1个桶中,一定会由空桶,则相邻两个数的最大值的差值
,一定出现在,最大连续空桶个数的左边第一个桶的最大值,和右边第一个桶的最小值。也可以说是每一个桶的最大值,和该桶右侧非空桶的最小值的差,数值最大的差。
因为桶内,两个元素的最大差值,一定是小于区间差值d的。
将n+1桶,和并到第n个桶内,此时就是n桶就是[]的。此时n个数,分散到n个桶里,没有空桶最分散的情况,也就是每个桶里一个元素,两个相邻元素的最大差值也是,每一个桶的最大值,和该桶右侧非空桶的最小值的差,数值最大的差
,如果出现空桶,和上面n+1个桶的情况就一致了。
所以,统计出每一个桶的最大值,和该桶右侧非空桶的最小值的差,数值最大的差即为原数组排序后的相邻最大差值。
代码
@SuppressWarnings("all")
public class MaxGroup {public static int getMaxGroup(int[] array) {int arrayLen = array.length;if (arrayLen < 2)return 0;//1.得到数列的最大值和最小值int max = array[0];int min = array[0];for (int i = 1; i < arrayLen; i++) {if (max < array[i])max = array[i];if (min > array[i])min = array[i];}int d = max - min;if (d == 0)return 0;//2.初始化桶int bucketNum = arrayLen;Bucket[] buckets = new Bucket[bucketNum];for (int i = 0; i < bucketNum; i++)buckets[i] = new Bucket();//3.遍历原始数组,确定每个桶的最大最小值for (int i = 0; i < arrayLen; i++) {int index = ((array[i] - min) / d * (bucketNum - 1));//求出当前元素,在整体区间的比值,再放大(len - 1)倍就是桶(所在区间)的索引 index + 1是桶的个数if (buckets[index].getMin() == null || buckets[index].getMin() > array[i])buckets[index].setMin(array[i]);if (buckets[index].getMax() == null || buckets[index].getMax() < array[i])buckets[index].setMax(array[i]);}//4.遍历桶,找到最大差值int leftMax = buckets[0].getMax();int maxGroup = 0;for (int i = 1; i < bucketNum; i++) {if (buckets[i].getMin() == null)continue;//空桶跳过,如果桶非空,则该桶的min和max值,一定不为空int differNum = buckets[i].getMin() - leftMax;if (differNum > maxGroup)maxGroup = differNum;leftMax = buckets[i].getMax();//}return maxGroup;}private static class Bucket {Integer min;Integer max;public Integer getMin() {return min;}public void setMin(int min) {this.min = min;}public Integer getMax() {return max;}public void setMax(int max) {this.max = max;}}public static void main(String[] args) {int[] array = new int[]{2, 5, 3, 4, 5, 10, 8};System.out.println(getMaxGroup(array));}}