给你一个整数数组 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. 关于failed to load resource 问题的处理

    问题: c++做插件,写了一个native class,继承于ue的类ActorComponent,而蓝图里也继承了这个c++ class,都在插件里,每次打开的时候就有这个错误: 之前的解决办法,复 ...

  2. java面试一日一题:说下mysql中的binlog

    问题:请讲下mysql中的binlog 分析:该问题主要考察对mysql中binlog的理解及使用场景? 回答要点: 主要从以下几点去考虑, 1.什么是binglog? 2.binlog的使用场景是什 ...

  3. scratch源码下载 | 超大太空游戏【80MB】

    按方向键或AWSD键控制角色移动,按空格键或X键攻击. 程序超级大,共80MB,耐心等待加载. 截图: 点击下载源码 更多源码访问:小虎鲸scratch资源站

  4. python adb 安卓app性能测试

    主要是进行cpu.内存.冷启动.热启动.流量.电量的监测 可获取到相关数据,同竞类产品对比,或者同版本对比 cpustatus adb命令:adb shell "dumpsys cpuinf ...

  5. 使用 Alba 对 AspnetCore项目进行测试

    前言 在AspnetCore生态系统中,我们测试项目一般使用Microsoft.AspNetCore.TestHost的TestServer 到.NET6后提供的Microsoft.AspNetCor ...

  6. tensorflow 读、存取 图像 数据的 TFRecord 方法 (示例)

    1.     利用TFRecord 格式   读.存 取    Mnist数据集的方法 存取   Mnist数据集的方法     (TFRecord格式) import tensorflow as t ...

  7. git submodule子模块操作

    背景 为什么使用子模块,因为需要使用其他人维护的公共组件,但这些组件并不是以包或库的形式使用的.所以采用子模块的形式,无论是自己修改还是拉取也很方便. 子模块操作 增加子模块 git submodul ...

  8. 宝塔环境安装redis

    参考: http://www.bt.cn/Help/Find?id=92 步骤: 1. 在安装宝塔时 PHP 版本选 7.0: 2. 安装 redis:wget http://125.88.182.1 ...

  9. IDEA-实时显示当前所在类及方

    有时候用GIT对比文件修改过大,没法同步修改的时候,这个操作方式就变得极为有用.接下来就是是实操. 1 view 2 Active Editor 3 勾上show Breadcrumbs 4 看IDE ...

  10. 一种很变态但有效的DDD建模沟通方式

    本文书接上回<这就是为什么你学不会DDD>,关注公众号(老肖想当外语大佬)获取信息: 最新文章更新: DDD框架源码(.NET.Java双平台): 加群畅聊,建模分析.技术实现交流: 视频 ...