1. 题目来源
2. 题目说明
3. 题目解析
方法一:暴力投机+常规解法
很暴力的一个暴力解法,加上一个特判就过了,若数组的最大项减去最小项还小于等于 limit
的话,说明应该返回整个数组长度。这个可有效避免重复项…但这个属实有点投机了,不推荐,但是真香 😃。
参见代码如下:
// 执行用时 :124 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :30.3 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int res = 0, c = nums[0], d = nums[0];
for (auto e : nums) c = max(c, e), d = min(d, e);
if (abs(c - d) <= limit) return nums.size();
for (int i = 0; i < nums.size(); ++i) {
int mx = nums[i], mi = nums[i], j = i;
for (j; j < nums.size(); ++j) {
mx = max(mx, nums[j]);
mi = min(mi, nums[j]);
if (abs(mx - mi) > limit) break;
}
res = max(res, j - i);
}
return res;
}
};
方法二:优先队列+双指针+巧妙解法
这道题符合双指针思想,即固定 left
使 right
在条件下不断向右移动,移动到 n
或者未在条件内就跳出循环。采用两个优先队列来求出区间的最大、最小值。这个的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),并且采用优先队列求最大值就正常数据输入即可,求最小值时可以采用给数据乘负号的形式输入,输出时再乘负号即可。在此 make_pair
是一个函数,无法使用 typedef
,就使用简单的宏替换即可,相当于字符串替换。但还是尽量少用宏定义吧。
不过这执行用时真的离谱了点…确实最后一个 case
很顶啊,不过这个解法确实能有效通过最后一个用例。
参见代码如下:
// 执行用时 :468 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :34.7 MB, 在所有 C++ 提交中击败了100.00%的用户
typedef pair<int, int> PII;
#define MP(x, y) make_pair(x, y)
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int ans = 0, n = nums.size();
priority_queue<PII> mxq, miq;
for (int i = 0, r = 0; i < n; ++i) {
while (!mxq.empty() and mxq.top().second < i) mxq.pop();
while (!miq.empty() and miq.top().second < i) miq.pop();
int mx = 0, mi = 1e9 + 1;
if (!mxq.empty()) mx = mxq.top().first;
if (!mxq.empty()) mi = -miq.top().first;
while (r < n and max(mx, nums[r]) - min(mi, nums[r]) <= limit) {
mxq.push(MP(nums[r], r));
miq.push(MP(-nums[r], r));
mx = max(mx, nums[r]);
mi = min(mi, nums[r]);
++r;
}
ans = max(ans, r - i);
}
return ans;
}
};