【中等】数组排序之后相邻数的最大差值-Java

该教程介绍了一种使用桶排序思想解决数组排序后相邻数最大差值问题的方法。通过计算每个数的桶号,记录每个桶的最大值和最小值,从而在O(N)的时间复杂度内找到最大差值,避免了O(NlogN)的排序成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程大家好!欢迎来到我的网站! 人工智能被认为是一种拯救世界、终结世界的技术。毋庸置疑,人工智能时代就要来临了,科… 继续阅读 前言https://www.captainai.net/troubleshooter

package live.every.day.ProgrammingDesign.CodingInterviewGuide.ArrayAndMatrix;

/**
 * 数组排序之后相邻数的最大差值
 *
 * 【题目】
 * 给定一个整型数组arr,返回排序后的相邻两数的最大差值。
 *
 * 【举例】
 * arr=[9,3,1,10],如果排序,结果为[1,3,9,10],9和3的差为最大差值,故返回6。
 * arr=[5,5,5,5],返回0。
 *
 * 【要求】
 * 如果arr的长度为N,请做到时问复杂度为O(N)。
 *
 * 【难度】
 * 中等
 *
 * 【解答】
 * 本题如果用排序法实现,其时间复杂度是O(NlogN),而如果利用桶排序的思想(不是直接进行桶排序),可以做到时间复杂度为O(N),
 * 额外空间复杂度为O(N)。遍历arr找到最小值和最大值,分别记为min和max。如果arr的长度为N,那么我们准备N+1个桶,把max单
 * 独放在第N+1号桶里。arr中在[min,max)范围上的数放在1~N号桶里,对于1~N号桶中的每一个桶来说,负责的区间大小为
 * (max-min)/N。比如长度为10的数组arr中,最小值为10,最大值为110。那么就谁备11个桶,arr中等于110的数全部放在第11号
 * 桶里。区间[10,20)的数全部放在1号桶里,区间[20,30)的数全部放在2号桶里,...,区间[100,110)的数全部放在10号桶里。那
 * 么如果一个数为num,它应该分配进(num-min)*len/(max-min)号桶里。
 * arr一共有N个数,min一定会放进1号桶里,max一定会放进最后的桶里,所以,如果把所有的数放入N+1个桶中,必然有桶是空的。如
 * 果arr经过排序,相邻的数有可能此时在同一个桶中,也可能在不同的桶中。在同一个桶中的任何两个数的差值都不会大于区间值,而
 * 在空桶左右两边不空的桶里,相邻数的差值肯定大于区间值。所以产生最大差值的两个相邻数肯定来自不同的桶。所以只要计算桶之间
 * 数的间距就可以,也就是只用记录每个桶的最大值和最小值,最大差值只可能来自某个非空桶的最小值减去前一个非空桶的最大值。
 * 具体过程请参看如下代码中的maxGap方法。
 *
 * @author Created by LiveEveryDay
 */

public class ArraySortedAdjacentMaxGap {

    public static int maxGap(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        int len = nums.length;
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < len; i++) {
            min = Math.min(min, nums[i]);
            max = Math.max(max, nums[i]);
        }
        if (min == max) {
            return 0;
        }
        boolean[] hasNum = new boolean[len + 1];
        int[] maxs = new int[len + 1];
        int[] mins = new int[len + 1];
        int bid = 0;
        for (int i = 0; i < len; i++) {
            bid = bucket(nums[i], len, min, max); // 算出桶号
            mins[bid] = hasNum[bid] ? Math.min(mins[bid], nums[i]) : nums[i];
            maxs[bid] = hasNum[bid] ? Math.max(maxs[bid], nums[i]) : nums[i];
            hasNum[bid] = true;
        }
        int res = 0;
        int lastMax = 0;
        int i = 0;
        while (i <= len) {
            if (hasNum[i++]) { // 找到第一个不为空的桶
                lastMax = maxs[i - 1];
                break;
            }
        }
        for (; i <= len; i++) {
            if (hasNum[i]) {
                res = Math.max(res, mins[i] - lastMax);
                lastMax = maxs[i];
            }
        }
        return res;
    }

    // 使用long类型是为了防止相乘时溢出
    private static int bucket(long num, long len, long min, long max) {
        return (int) ((num - min) * len / (max - min));
    }

    public static void main(String[] args) {
        int[] arr = {9, 3, 1, 0};
        System.out.printf("The max gap is: %d", maxGap(arr));
    }

}

// ------ Output ------
/*
The max gap is: 6
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值