LeetCode 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit (绝对差不超过限制的最长连续子数组)
给你一个整数数组 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 (绝对差不超过限制的最长连续子数组)的更多相关文章
- 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 ...
- 【LeetCode】1438. 绝对差不超过限制的最长连续子数组 Longest Continuous Subarray With Absolute Diff Less Than or Equal t
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 滑动窗口 日期 题目地址:https://leetco ...
- 力扣1438. 绝对差不超过限制的最长连续子数组-C语言实现-中等难度
题目 传送门 文本 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit . 如果不存在满足条 ...
- [LeetCode] Shortest Unsorted Continuous Subarray 最短无序连续子数组
Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...
- lintcode :continuous subarray sum 连续子数组之和
题目 连续子数组求和 给定一个整数数组,请找出一个连续子数组,使得该子数组的和最大.输出答案时,请分别返回第一个数字和最后一个数字的值.(如果两个相同的答案,请返回其中任意一个) 样例 给定 [-3, ...
- 【LeetCode】Maximum Product Subarray 求连续子数组使其乘积最大
Add Date 2014-09-23 Maximum Product Subarray Find the contiguous subarray within an array (containin ...
- Maximum Subarray 连续子数组最大和
Find the contiguous subarray within an array (containing at least one number) which has the largest ...
- leetcode面试题42. 连续子数组的最大和
总结一道leetcode上的高频题,反反复复遇到了好多次,特别适合作为一道动态规划入门题,本文将详细的从读题开始,介绍解题思路. 题目描述示例动态规划分析代码结果 题目 面试题42. 连续子数 ...
- [LeetCode] 674. Longest Continuous Increasing Subsequence_Easy Dynamic Programming
Given an unsorted array of integers, find the length of longest continuous increasing subsequence (s ...
- LeetCode 674. Longest Continuous Increasing Subsequence (最长连续递增序列)
Given an unsorted array of integers, find the length of longest continuous increasing subsequence. E ...
随机推荐
- Asp.Net Core之Identity源码学习
什么是Identity ASP.NET Identity是构建核心 Web 应用程序(ASP.NET.登录和用户数据)的成员系统.ASP.NET核心标识允许您向应用程序添加登录功能,并可以轻松自定义有 ...
- 如何计算两个正太分布的KL散度 —— 正太分布的KL散度 (Kullback-Leibler divergence) 计算
参考: https://blog.csdn.net/int_main_Roland/article/details/124650909 给出实现代码: def get_kl(): mean0, log ...
- 如何将python的pip源设置为阿里云
为python的pip源设置为阿里云,pip源的设置操作: pip config set global.index-url https://mirrors.cloud.aliyuncs.com/pyp ...
- 深度解读KubeEdge架构设计与边缘AI实践探索
摘要:解读业界首个云原生边缘计算框架KubeEdge的架构设计,如何实现边云协同AI,将AI能力无缝下沉至边缘,让AI赋能边侧各行各业,构建智能.高效.自治的边缘计算新时代,共同探索智能边缘的新篇章. ...
- Java学习笔记1--JDK,JRE和JVM
1.Java开发环境 Java开发环境是指Java程序员开发.编写.测试和调试Java程序所使用的所有工具和技术.Java开发环境通常由以下几个部分组成: JDK(Java Development K ...
- Java IO流的简单使用 通俗易懂 超详细 【内含案例】
IO流简单使用 InputStream 字节输入流 OutputStream 字节输出流 Reader 字符输入流 Writer 字符输出流 代码示例 输入和输出是相对于程序来说的,读取到程序中叫做输 ...
- 利用Makefile给多文件、多目录C源码建立工程
0. 前言 粉丝留言,想知道如何使用Makefile给多个文件和多级目录建立一个工程,必须安排! 关于Makefile的入门参考文章,可以先看这篇文章: <Makefile入门教程> 为了 ...
- Mybatis Log 插件
目前的idea插件已经开始收费---找了一个免费的插件安装到idea中重启一下就可以了 百度网盘提取码:sjc8
- vscode注释快捷键
单行注释 ctrl+/ 多行注释 ctrl+alt+a 文档注释 /** 复制上面一行 ctrl+d 选中段落整体向左或向右缩进 ctrl +[ 或 ctrl + ] 查找 ctrl + f
- Vite+Vue3 项目 华仔待办
此"华仔",不是彼"华仔",你懂的! 先来了个截图 紧跟着,实现步骤也来了 1. 安装 Node.js,终端运行 npm create vue@latest,项 ...