无需数组排序后的最大相邻差
题目
有一个无序整型数组,如何求出该数组排序后的任意两个相邻元素的最大差值?要求时间和空间复杂度尽可能低。
思路
解法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));
}
}