leetcode:164. 无序数组如果排序之后相邻数之间的最大差值

这篇博客介绍了如何运用桶排序算法解决LeetCode中的164.最大间距问题。通过假设数组区间并进行等分,创建桶来存储数值,然后找到空桶两侧的最大值和最小值来确定最大间距。这种方法有效地减少了比较次数,提高了效率。博客还讨论了如何确定数值应放入哪个桶,并提供了具体的代码实现。

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

题目来源

题目描述

在这里插入图片描述

class Solution {
public:
    int maximumGap(vector<int>& nums) {

    }
};

题目解析

桶排序

借助桶排序的思想,假设答案法。

整个数组假设一共有9个数,其最小值是0,最大值是99。

那么我们将整个范围[0,99]10等分。

  • 为什么是10等分,因为一共有9个数
  • 如果有10个数,那么就将[0,99]11等分
  • 如果有11个数,那么就将[0,99]12等分
  • 如果有N个数,那么就把从[最小值,最大值]一共N+1等分

从而得到了10个桶:

  • 第0个桶只收集范围在0~10区间的数
  • 第1个桶只收集范围在11~21区间的数
  • 第2个桶只收集范围在22~32区间的数
  • 第3个桶只收集范围在33~43区间的数
  • 第4个桶只收集范围在44~54区间的数
  • 最后一个空只收集99

因此:

  • 最小值一定会进最左边的桶,最大值一定会近最右边的桶
    • (所以空桶一定不会出现在左右两侧)
    • 可能会存在多个空桶,空桶的边上可能是空桶
  • 一共有10个桶,但是只有9个数,所以中间一定会有一个空桶

如果拍完序之后: 相邻两数就可能来自同一个桶,也可能来自跨桶的

  • 空桶的左右两侧一定存在非空桶:
    • 左侧的非空桶的最大值,和左侧的非空桶的最小值一定相邻,而且它们之间的差值一定大于桶范围
    • 来自同一个桶的数一定不是我们要找的。因为同一个桶的相邻数减完之后差值不会大于桶区间;
    • 这就排除了一大票可能的数,因此每个桶我们只需要维护其最大值和最小值即可,完全不需要考虑桶内的数据是怎么分布的
  • 最大值一定来自空桶两侧吗?不一定

问题:怎么决定nums[i]应该进哪个桶?

int bucket(int num, int len, int min, int max){
    return (int) ((num - min) * len / (max - min));
}

怎么分,不重要,关键是桶排序

举个例子

在这里插入图片描述

实现

class Solution {
    int bucket(long num, long len, long min, long max) {
        return (int) ((num - min) * len / (max - min));
    }
public:
    int maximumGap(vector<int>& nums) {
        if(nums.size() < 2){
            return 0;
        }

        int len = nums.size();
        int min = INT32_MAX, max = INT32_MIN;
        for (int i = 0; i < len; ++i) {
            min = std::min(min, nums[i]);
            max = std::max(max, nums[i]);
        }
        if(max == min){
            return 0;
        }
        int bucketSize = len + 1;
        std::vector<bool> hasNum(len + 1, false);
        std::vector<int> maxs(len + 1, INT32_MIN);
        std::vector<int> mins(len + 1, INT32_MAX);
        int bid = 0;
        for (int i = 0; i < len; i++) {
            bid = bucket(nums[i], bucketSize - 1 , min, max);
            mins[bid] = hasNum[bid] ? std::min(mins[bid], nums[i]) : nums[i];
            maxs[bid] = hasNum[bid] ? std::max(maxs[bid], nums[i]) : nums[i];
            hasNum[bid] = true;
        }

        int ans = INT32_MIN;
        int lasMax = maxs[0];  // 左右两侧一定不是空桶
        for (int i = 1; i <= len; ++i) {
            if(hasNum[i]){
                ans = std::max(ans, mins[i] - lasMax); //相邻的数
                lasMax = maxs[i];
            }
        }
        return ans;
    }
};

桶排序

在这里插入图片描述


基数排序

给定一个整数组 nums 和一个目标值 target,要求在数组中找出个数的和等于目标值,并返回这个数的索引。 思路1:暴力法 最简单的思路是使用层循环遍历数组的所有组合,判断个数的和是否等于目标值。如果等于目标值,则返回这个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前个指针指向的的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值