给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。

如果不存在满足条件的子数组,则返回 0 。

示例 1:

输入:nums = [8,2,4,7], limit = 4
输出:2
解释:所有子数组如下:
[8] 最大绝对差 |8-8| = 0 <= 4.
[8,2] 最大绝对差 |8-2| = 6 > 4.
[8,2,4] 最大绝对差 |8-2| = 6 > 4.
[8,2,4,7] 最大绝对差 |8-2| = 6 > 4.
[2] 最大绝对差 |2-2| = 0 <= 4.
[2,4] 最大绝对差 |2-4| = 2 <= 4.
[2,4,7] 最大绝对差 |2-7| = 5 > 4.
[4] 最大绝对差 |4-4| = 0 <= 4.
[4,7] 最大绝对差 |4-7| = 3 <= 4.
[7] 最大绝对差 |7-7| = 0 <= 4.
因此,满足题意的最长子数组的长度为 2 。

比赛时这破题真就卡了一个小时= = 然后第四题没来记得看= = 我好菜啊

解法1、树状数组/线段树 求区间极值 + 二分

树状数组求区间最大最小值 logn 二分长度然后枚举起点 时间复杂度 O(logn * logn * n)

线段树 太久没写了 练下手。不过这题比较简单,没有更新,没有什么pushup pushdown的操作

#define lson (o<<1)
#define rson (o<<1|1)
#define mid ((l+r)>>1) const int N = 100005;
int max_tr[N * 3], min_tr[N * 3]; class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int n = nums.size();
build(1, 1, n, nums);
int l = 1, r = n;
int ans = 0;
// 二分长度
while (l <= r) {
int m = (l + r) >> 1;
bool f = false;
for (int i = 0, j; (j = i + m - 1) < n; i++) {
int maxv = query_max(1, 1, n, i + 1, j + 1);
int minv = query_min(1, 1, n, i + 1, j + 1);
if (maxv - minv <= limit) {
f = true;
break;
}
}
if (f) ans = m, l = m + 1;
else r = m - 1;
}
return ans;
}
void build(int o, int l, int r, vector<int>& nums) {
if (l == r) {
max_tr[o] = min_tr[o] = nums[l - 1];
return ;
}
build(lson, l, mid, nums);
build(rson, mid + 1, r, nums);
pushup(o);
}
void pushup(int o) {
max_tr[o] = max(max_tr[lson], max_tr[rson]);
min_tr[o] = min(min_tr[lson], min_tr[rson]);
}
int query_min(int o, int l, int r, int L, int R) {
if (l >= L && r <= R) return min_tr[o];
int res = INT_MAX;
if (L <= mid) res = min(res, query_min(lson, l, mid, L, R));
if (R > mid) res = min(res, query_min(rson, mid + 1, r, L, R));
return res;
}
int query_max(int o, int l, int r, int L, int R) {
if (l >= L && r <= R) return max_tr[o];
int res = 0;
if (L <= mid) res = max(res, query_max(lson, l, mid, L, R));
if (R > mid) res = max(res, query_max(rson, mid + 1, r, L, R));
return res;
}
};

树状数组 求区间极值我一直不会。。。so。。比赛时现搜的代码,然后找了一个错误的,调了半个小时。。。又换了一个博客才AC。QAQ

const int N = 100005;
int arrmi[N], arrmx[N]; class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int n = nums.size();
init(nums);
int l = 1, r = n;
int ans = 0;
// 二分长度
while (l <= r) {
int m = (l + r) >> 1;
bool f = false;
for (int i = 0, j; (j = i + m - 1) < n; i++) {
int maxv = querymx(i + 1, j + 1, nums);
int minv = querymi(i + 1, j + 1, nums);
if (maxv - minv <= limit) {
f = true;
break;
}
}
if (f) ans = m, l = m + 1;
else r = m - 1;
}
return ans;
}
void init(vector<int>& nums) {
for(int i = 1; i <= nums.size(); ++i) arrmi[i] = INT_MAX;
for(int i = 1; i <= nums.size(); ++i)
for(int j = i; j <= nums.size() && arrmi[j] > nums[i - 1]; j += lowbit(j))
arrmi[j] = nums[i - 1]; memset(arrmx, 0, sizeof arrmx);
for(int i = 1; i <= nums.size(); ++i)
for(int j = i; j <= nums.size() && arrmx[j] < nums[i - 1]; j += lowbit(j))
arrmx[j] = nums[i - 1];
}
int querymx(int L, int R, vector<int>& nums) {
int res = 0;
for (--L; L < R; ){
if (R - lowbit(R) >= L) {
res = max(res, arrmx[R]); R -= lowbit(R);
} else {
res = max(res, nums[R - 1]);
--R;
}
}
return res;
}
int querymi(int L, int R, vector<int>& nums) {
int res = INT_MAX;
for (--L; L < R; ){
if (R - lowbit(R) >= L) {
res = min(res, arrmi[R]); R -= lowbit(R);
} else {
res = min(res, nums[R - 1]);
--R;
}
}
return res;
}
int lowbit(int x) { return x & -x; }
};

树状数组(1032 ms)比线段树(1944 ms)快一倍

解法2、multiset + 滑动窗口

我只能说STL是真的好用,但是我不太会用啊。。。。

multiset 能在 logn 的事件复杂度求出最大最小值,也能在 O(logn) 的复杂度增加删除元素

class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int n = nums.size();
multiset<int> st;
int l = 0, r = 0, ans = 0;
while (r < n) {
st.insert(nums[r++]);
while (*st.rbegin() - *st.begin() > limit) {
st.erase(st.find(nums[l++]));
}
ans = max(ans, r - l);
}
return ans;
}
};

md 10行代码,我看着我比赛写的100行代码真的好气。。然后只需要 260 ms。。。

解法3、双端队列 + 滑动窗口

class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int n = nums.size();
deque<int> deq; // 降序队列 记录最大值
deque<int> inq; // 升序队列 记录最小值
int l = 0, r = 0, ans = 0;
while (r < n) {
int x = nums[r];
while (deq.size() && nums[deq.back()] <= x) {
deq.pop_back();
}
deq.push_back(r);
while (inq.size() && nums[inq.back()] >= x) {
inq.pop_back();
}
inq.push_back(r);
while (nums[deq.front()] - nums[inq.front()] > limit) {
l++;
if (deq.front() < l) deq.pop_front();
if (inq.front() < l) inq.pop_front();
}
ans = max(ans, r - l + 1);
r++;
}
return ans;
}
};

感觉这种解法更妙一些,应该是 O(n) 的时间复杂度吧。132 ms 我之前应该是写过这种题,但是应该是很久以前了,只有浅浅的印象==

用两个双端队列记录每一个对最大最小值有贡献的位置

比如输入 [8,2,4,7] 4

初始化,l=0, r=0

deq [0] inq [0] // 都是[8]

最大值-最小值 = 8-8 = 0 <= 4 所以 子数组 [0,0] 长度为 1

右端向右移动,r=1

deq [0,1] inq [1] // 下标对应值 deq [8,2] inq [2]

对于inq,要知道计算是从前到后的 1 这个位置比 0 小,所以 0 这个位置对于最小值是没有贡献的,如果你想向前移动到最小值变大,一定要移动到 1 后面。这就是 inq 记录的下标的意义。

而对于 deq 我们记录的是对最大值右贡献的位置,如果你想最大值变小,那么 由 0->1 是由变化的,所以要留下 0 这个位置。

此时最大值 8 最小值 2,8-2>4 所以 l 应该向右移动。

l 向右移动 1,此时 l=1 所以 deq和inq中小于1的下标都应该被删除。

deq [1] inq [1] 最大值-最小值=1-1=0

此时子数组[1,1] 长度为1

r继续向右移动,r=2

deq[2] inq[1,2] // 对于值 deq[4]  inq[2,4]

最大值-最小值 = 4-2 = 2<=4

此时子数组[1,2] 长度为2

r继续向右移动,r=3

deq[3] inq[1,2,3] // 对于值 deq[7]  inq[2,4,7]

最大值-最小值 = 7-2 = 5>4,所以l需要向右移动

l=2, deq和inq中小于2的下标都应该被删除。

deq[3] inq[2,3] // 对于值 deq[7]  inq[4,7]

最大值-最小值 = 7-4 = 3<=4

此时子数组[2,3] 长度为2

所以最长的子数组长度为2。

LeetCode 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit (绝对差不超过限制的最长连续子数组)的更多相关文章

  1. 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit

    Given an array of integers nums and an integer limit, return the size of the longest continuous suba ...

  2. 【LeetCode】1438. 绝对差不超过限制的最长连续子数组 Longest Continuous Subarray With Absolute Diff Less Than or Equal t

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 滑动窗口 日期 题目地址:https://leetco ...

  3. 力扣1438. 绝对差不超过限制的最长连续子数组-C语言实现-中等难度

    题目 传送门 文本 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit . 如果不存在满足条 ...

  4. [LeetCode] Shortest Unsorted Continuous Subarray 最短无序连续子数组

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  5. lintcode :continuous subarray sum 连续子数组之和

    题目 连续子数组求和 给定一个整数数组,请找出一个连续子数组,使得该子数组的和最大.输出答案时,请分别返回第一个数字和最后一个数字的值.(如果两个相同的答案,请返回其中任意一个) 样例 给定 [-3, ...

  6. 【LeetCode】Maximum Product Subarray 求连续子数组使其乘积最大

    Add Date 2014-09-23 Maximum Product Subarray Find the contiguous subarray within an array (containin ...

  7. Maximum Subarray 连续子数组最大和

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  8. leetcode面试题42. 连续子数组的最大和

      总结一道leetcode上的高频题,反反复复遇到了好多次,特别适合作为一道动态规划入门题,本文将详细的从读题开始,介绍解题思路. 题目描述示例动态规划分析代码结果 题目   面试题42. 连续子数 ...

  9. [LeetCode] 674. Longest Continuous Increasing Subsequence_Easy Dynamic Programming

    Given an unsorted array of integers, find the length of longest continuous increasing subsequence (s ...

  10. LeetCode 674. Longest Continuous Increasing Subsequence (最长连续递增序列)

    Given an unsorted array of integers, find the length of longest continuous increasing subsequence. E ...

随机推荐

  1. 【AppStore】IOS应用上架Appstore的一些小坑

    前言 上一篇文章写到如何上架IOS应用到Appstore,其中漏掉了些许期间遇到的小坑,现在补上 审核不通过原因 5.1.1 Guideline 5.1.1 - Legal - Privacy - D ...

  2. SemanticKernel/C#:使用Ollama中的对话模型与嵌入模型用于本地离线场景

    前言 上一篇文章介绍了使用SemanticKernel/C#的RAG简易实践,在上篇文章中我使用的是兼容OpenAI格式的在线API,但实际上会有很多本地离线的场景.今天跟大家介绍一下在Semanti ...

  3. 【C】Re10 共用体、枚举、类型定义

    Union 联合体\共用体 结合体: 每个成员的内存空间都是独立存在的,互不干涉 int 成员.double 成员.char 成员 = 4 + 8 + 1 [13字节大小] 取成员字节占用之和作为这个 ...

  4. 给大家降降火 —— AI养殖是否夸大功效 —— 深大学生用AI养乌骨鸡增产6万只

    看到一个新闻: 地址: https://export.shobserver.com/baijiahao/html/705726.html 这个新闻里面说的就是这个腾讯的对口培养的大学生搞了一个AI养殖 ...

  5. 如何修复ubuntu的uefi启动——如何将Ubuntu安装入移动硬盘中

    交代一下使用场景,个人平时经常使用Ubuntu系统,由于不喜欢总在一个地方呆但是来回搬电脑又不是十分的方便,于是想到了一个好的方案,那就是把Ubuntu系统安装到移动硬盘中,这样不论是在家还是在实验室 ...

  6. 【转载】 tensorflow变量默认是如何进行初始化的?

    版权声明:本文为CSDN博主「TahoeWang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/sinat_3 ...

  7. nginx实战教程

    大纲 为了让大家更快的学会,该博客中的内容录制成了视频课程:马上在线学习 1.什么是nginx Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 由 ...

  8. Auto.js 入门教程(二)

    来了来了 ~ 下面开始学习auto.js 了! 准备材料 : android7.0及以上版本的手机一部(需要开启 '无障碍服务') auto.js软件 vscode (安装配套插件Auto.js-VS ...

  9. 【产品兼容认证】WhaleStudio 成功兼容TiDB数据库软件

    平凯星辰和白鲸开源宣布成功完成产品兼容认证 北京,2023年12月27日 - 平凯星辰(北京)科技有限公司(以下简称平凯星辰)旗下的 TiDB 产品与白鲸开源的 WhaleStudio 已成功完成产品 ...

  10. Apache SeaTunnel k8s 集群模式 Zeta 引擎部署指南

    SeaTunnel提供了一种运行Zeta引擎(cluster-mode)的方法,可以让Kubernetes在本地运行Zeta引擎,实现更高效的应用程序部署和管理.在本文中,我们将探索SeaTunnel ...