给你一个整数数组 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. Java--匿名类(学习笔记)

    匿名类的特点:(1) 匿名类是final类:(3) 在匿名类中可以定义实例变量和若干个实例初始化代码块和新的实例方法.Java虚拟机首先调用父类的构造方法,然后按照实例变量的和实例初始化代码块定义的先 ...

  2. 概述C#中各种类型集合的特点

    在C#中,集合是用于存储和操作一组数据项的数据结构.这些集合通常位于 System.Collections 和 System.Collections.Generic 命名空间中.下面我将概述C#中几种 ...

  3. 【Java】用户在线人数统计的简单实现

    一.需求效果: 就是进入首页时能查看在线人数,没有特定要求,那我就不刷这个接口了 就进入首页加载一次 二.实现思路: 思路参考博客: https://blog.csdn.net/GitLuckyd/a ...

  4. 学术写作: These authors contributed equally to this work. —— 共同一作

    早些年很少看到论文里面有: These authors contributed equally to this work. 不过现在这种方法在论文中出现的还是比较多的,说白了,这种共同一作的声明其实是 ...

  5. 强化学习:经典测试环境Cart-pole的原始文献

    参考文献格式: A. G. Barto, R. S. Sutton, and C. W. Anderson. Neuronlike adaptive elements that can solve d ...

  6. 【转载】 DeepMind 提出元梯度强化学习算法,显著提高大规模深度强化学习应用的性能

    原文地址: https://www.jiqizhixin.com/articles/053104 李亚洲翻译 2018/05/31 12:38 Pedro 路参与 ================== ...

  7. Python使用pynvml查看GPU信息

    参考: https://blog.csdn.net/TracelessLe/article/details/107405544 ==================================== ...

  8. AMiner的数据质量和完善问题

    最近参加到了一个国家科技项目中,这里就不吐槽这种高校承接国家科技项目是一件多么不靠谱的事情了,这里就说说我们的对标产品"AMiner".补充一下,虽然个人对AMiner的评价不是很 ...

  9. bazel编译报错:absl/base/policy_checks.h:79:2: error: #error "C++ versions less than C++14 are not supported."

    使用bazel编译一个软件时报错,报错的信息为: absl/base/policy_checks.h:79:2: error: #error "C++ versions less than ...

  10. 一文讲清楚static关键字

    static能修饰的地方 静态变量 静态变量: 又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它:静态变量在内存中只存在一份. 实例变量: 每创建一个实例就 ...