LeetCode 164 最大间隔

LeetCode 164 最大间隔

1. 题目地址

    https://leetcode.cn/problems/maximum-gap/submissions/

2. 题目解析

    本题要求在线性复杂度的情况下,求出一组数在数轴上的最大间隔。
    这道题直观的解法:先排序,在依次遍历,找到最大间隔就完成了。但是,排序算法最好的时间复杂度都是O(nlogn)。因此,这道题采用排序算法是不可行的。
    因此,我们要采用桶排序的思想来求解这道题。

3. 题解

    在阐述步骤之前,我们要了解一个性质:设长度为N的数组中的最大值和最小值分别为:maxmin。则在数轴上,相邻数字的最大间距不小于⌈(max-min) / N-1⌉。(注意:这里是向上取整)  
    我们采用反证法进行证明:假设在数轴上,相邻数字的最大间距小于⌈(max-min) / N-1⌉。那么,记:将数字排完序后,在数轴上的数字分别为A1 A2 ... AN。
    则:AN - A1 = (A2 - A1) + (A3 - A2) + ... + (AN - AN-1)。
       AN - A1 < (max - min) / N-1 + (max - min) / N-1 + ... + (max - min) / N-1。
       AN - A1 < (N-1)*(max - min) / N-1。
       AN - A1 < max - min
       矛盾。因为:根据上述假设:AN 一定为最大值。A1一定为最小值。
    因此,我们可以开辟大小为(max-min) / N-1的桶。这样的话,如果要求出相邻数字的最大间隔的话。根据上述性质:最大间隔一定在桶间,不会再桶内(除非这一组数字均相等,换句话说:最大值和最小值相等)。
    当我们开辟了桶之后,我们就可以将数字放入桶中。在每个桶中均要记录最大值和最小值。
    最后,从前往后遍历每一个桶。
        1.  如果桶只有一个,那么直接返回0。因为此时,最大值和最小值一定相等。
        2.  如果桶的数量>=1,则遍历每一个桶。(计算上一个桶的最大值 - 当前桶的最小值)求max即可得到答案。
    在上述过程中,我们要注意如下内容:
        1.  如果给定的一组数中,发现最大值和最小值相等。那么,桶的长度bucketLength会为0。因此,对于如上情况,我们至少应该让桶的长度为12.  如何计算桶的个数?我们让最大值 - 最小值 / 桶的长度 + 1。就可以计算出桶的个数。
            2.1 其中,最大值 - 最小值 代表最大值和最小值的距离。
            2.2 除以桶的长度代表跨越了多少个桶。
            2.3 加一代表给最大值留一个桶。
        3.  如果最大值和最小值不相等,那么桶的个数至少为24.  如何将数字放入到指定的桶中?我们可以让nums[i] - 最小值 / 桶的长度即可。原因和计算桶的个数是一样的。
        5.  需要注意的是,在上述过程中,难免会有空桶的情况出现。因此,在计算最大间距的时候,我们应该要跨过空桶进行计算。

4. 代码

//数据为整数
class Solution {
public:
    int maximumGap(vector<int>& nums) {
        int length = nums.size();
        if(length < 2){
            return 0;
        }
        int maxValue = 0;
        int minValue = 0x3f3f3f3f;
        for(int i = 0; i < length; i ++){
            if(maxValue < nums[i]){
                maxValue = nums[i];
            }
            if(minValue > nums[i]){
                minValue = nums[i];
            }
        }
        //计算桶长度
        int bucketLength = max(1,(maxValue - minValue) / (length - 1));
        //计算桶个数
        int bucketCount = (maxValue - minValue) / bucketLength + 1;
        //声明桶
        int bucket[bucketCount][2];
        //初始化每个桶的最大和最小值(初始化为-1)
        memset(bucket,-1,sizeof(bucket));
        //往桶中放数
        for(int i = 0; i < length; i ++){
            //代表每一个数应该要放入哪个桶中
            int location = (nums[i] - minValue) / bucketLength;
            //如果桶为空桶
            if(bucket[location][0] == -1){
                bucket[location][0] = nums[i];
                bucket[location][1] = nums[i];
            }else{
                //如果桶中已经有数
                bucket[location][0] = min(bucket[location][0],nums[i]);
                bucket[location][1] = max(bucket[location][1],nums[i]);
            }
        }
        //如果桶的个数为1,此时最大值和最小值一定相等。
        //直接返回0即可。
        if(bucketCount == 1){
            return 0;
        }

        //遍历桶,得出最大间隔,双指针
        //最大间隔
        int maxGap = 0;
        //代表上一个桶
        int prev = -1;
        for(int i = 0; i < bucketCount;i ++){
            //如果是空桶,那么不计算
            if(bucket[i][0] == -1){
                continue;
            }
            //如果当前桶和上一个桶均不是空桶,那么计算最大间距
            if(prev != -1){
                maxGap = max(maxGap,bucket[i][0] - bucket[prev][1]);
            }
            //更新上一个桶
            prev = i;
        }

        return maxGap;
    }
};
//数据为浮点数,非本题代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;

int n;

vector<double> nums;

int main()
{
    scanf("%d", &n);;
    for (int i = 0; i < n; i++)
    {
        double number;
        scanf("%lf",&number);
        nums.push_back(number);
    }
    // //手动编写测试案例
    // nums.push_back(2.3);
    // nums.push_back(3.1);
    // nums.push_back(7.5);
    // nums.push_back(1.5);
    // nums.push_back(6.3);

    int length = nums.size();

    double maxValue = -0x3f3f3f3f;
    double minValue = 0x3f3f3f3f;

    // 确定数组的最大值,最小值
    for (int i = 0; i < length; i++)
    {
        if (nums[i] > maxValue)
        {
            maxValue = nums[i];
        }
        if (nums[i] < minValue)
        {
            minValue = nums[i];
        }
    }

    // 确定桶的大小(MaxValue - MinValue) / length - 1
    double bucketLength = max(1.0, (maxValue - minValue) / (length - 1));
    // 确定桶的个数(给最大值需要留一个桶)
    long long bucketCount = ceil((maxValue - minValue) / bucketLength + 1);
    // 定义桶
    double bucket[bucketCount][2] = {-1.0, -1.0};
    for (int i = 0; i < bucketCount; i++)
    {
        bucket[i][0] = -1.0;
        bucket[i][0] = -1.0;
    }
    // 遍历元素,放置在桶中
    for (int i = 0; i < length; i++)
    {
        // 计算出桶的坐标
        long long location = ceil((nums[i] - minValue) / bucketLength);
        // 如果桶中无数
        if (bucket[location][0] == -1.0)
        {
            bucket[location][0] = bucket[location][1] = nums[i];
        }
        else
        {
            // 如果桶中已有数,放置桶中,并更新桶的最大值和最小值
            bucket[location][0] = min(bucket[location][0], nums[i]);
            bucket[location][1] = max(bucket[location][1], nums[i]);
        }
    }
    // 如果桶只有一个,最大间隙就是桶内元素最大值-桶内元素最小值
    if (bucketCount == 1)
    {
        return bucket[0][1] - bucket[0][0];
    }
    // 计算间隔,从而得到最大间隔
    // 遍历非空桶,得出最终答案
    double maxGap = 0.0;
    int prev = -1;
    for (int i = 0; i < bucketCount; i++)
    {
        if (bucket[i][0] == -1)
        {
            continue;
        }
        if (prev != -1)
        {
            maxGap = max(maxGap, bucket[i][0] - bucket[prev][1]);
        }
        prev = i;
    }
    printf("%.1lf", maxGap);
    return 0;
}
posted @   夏目^_^  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示