作者:MJ昊
公众号:程序猿的编程之路
今天是 昊 的算法之路第10天,今天分享的是LeetCode第1438题绝对差不超过限制的最长连续子数组的解题思路。这道题目难度为中等
,通过滑动窗口与双端队列可以高效解决问题。
题目描述简要回顾
题目要求我们找到一个连续子数组,使得该子数组中最大值与最小值的绝对差不超过给定的 limit
,并返回满足条件的最长子数组的长度。
解题思路
本题可以通过滑动窗口和双端队列来高效解决。
- 使用两个双端队列
queMax
和queMin
分别存储当前窗口内的最大值和最小值。 - 我们将右边界
right
向右移动,不断扩大窗口。 - 每次移动
right
后,分别维护queMax
和queMin
,确保queMax
中的数值是递减的,queMin
中的数值是递增的,以快速找到当前窗口的最大值和最小值。 - 当
queMax
的最大值与queMin
的最小值之差大于limit
时,开始移动左边界left
,直到差值回到符合要求的范围。 - 每次移动后,更新最大长度
ret
。
代码实现:
var longestSubarray = function(nums, limit) { const queMax = []; const queMin = []; const n = nums.length; let left = 0, right = 0; let ret = 0; while (right < n) { // 维护 queMax 使其为递减队列 while (queMax.length && queMax[queMax.length - 1] < nums[right]) { queMax.pop(); } // 维护 queMin 使其为递增队列 while (queMin.length && queMin[queMin.length - 1] > nums[right]) { queMin.pop(); } queMax.push(nums[right]); queMin.push(nums[right]); // 当窗口内最大值与最小值的差值超过 limit 时,移动左边界 while (queMax.length && queMin.length && queMax[0] - queMin[0] > limit) { if (nums[left] === queMin[0]) { queMin.shift(); } if (nums[left] === queMax[0]) { queMax.shift(); } left++; } // 更新最大长度 ret = Math.max(ret, right - left + 1); right++; } return ret; };
复杂度分析
- 时间复杂度:O(n),其中
n
是数组nums
的长度。每个元素最多被加入和移除队列一次,因此时间复杂度是线性的。 - 空间复杂度:O(n),双端队列的空间最多为数组的长度。
总结
这道题通过滑动窗口结合双端队列有效解决了寻找最长符合条件的子数组的问题,滑动窗口技巧帮助我们在线性时间内找到符合要求的子数组,保证了算法的高效性。