LeetCode 164 最大间隔
1. 题目地址
https://leetcode.cn/problems/maximum-gap/submissions/
2. 题目解析
本题要求在线性复杂度的情况下,求出一组数在数轴上的最大间隔。
这道题直观的解法:先排序,在依次遍历,找到最大间隔就完成了。但是,排序算法最好的时间复杂度都是O(nlogn)。因此,这道题采用排序算法是不可行的。
因此,我们要采用桶排序的思想来求解这道题。
3. 题解
在阐述步骤之前,我们要了解一个性质:设长度为N的数组中的最大值和最小值分别为:max和min。则在数轴上,相邻数字的最大间距不小于⌈(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。因此,对于如上情况,我们至少应该让桶的长度为1。
2. 如何计算桶的个数?我们让最大值 - 最小值 / 桶的长度 + 1。就可以计算出桶的个数。
2.1 其中,最大值 - 最小值 代表最大值和最小值的距离。
2.2 除以桶的长度代表跨越了多少个桶。
2.3 加一代表给最大值留一个桶。
3. 如果最大值和最小值不相等,那么桶的个数至少为2。
4. 如何将数字放入到指定的桶中?我们可以让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];
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]);
}
}
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);
}
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];
}
}
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现