无需数组排序后的最大相邻差

题目

有一个无序整型数组,如何求出该数组排序后的任意两个相邻元素的最大差值?要求时间和空间复杂度尽可能低。

思路

解法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));

    }

}
posted @ 2024-12-18 22:35  长名06  阅读(22)  评论(0编辑  收藏  举报