本文已参与「新人创作礼」活动,一起开启掘金创作之路。
左右指针
在有序数组中,将指向最左侧的索引定义为左指针(left),最右侧的定义为右指针(right),然后从两头向中间进行数组遍历。
左右指针主要用于解决数组(或者字符串)中的问题:
- 二分查找:定义一左一右两个指针,然后向中间遍历,直到满足条件或者两个指针相遇。
- 滑动窗口:两个指针,一前一后组成滑动窗口,并计算滑动窗口中的元素的问题。
左右指针的相关题目
题型1 - 二分查找
参考二分法 ☞ 传送门
题型2 - 滑动窗口
-
题目:
209. 长度最小的子数组
Medium:给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 -
思路:
使用一层for循环,遍历窗口的终止位置,当终止位置移动时(即放大窗口将符合的目标集合包进窗口)到符合目标集合的位置时,开始移动起始位置,即缩小窗口,判断是否依旧满足≥target的要求,并存储最小。起始位置移动(窗口缩小)到第一个不满足≥target的窗口时,终止位置继续移动。知道循环结束,
-
代码:
// @lc code=start
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
let sum = 0 // 最小子数组的和
// 最后的结果,子数组一定小于原数组长度,为了便于后面比较,这里取一个大于最大长度的值。
let result = nums.length + 1
let subLen = 0 // 当前子数组长度
// 滑动窗口
let start = 0 // 起始位置
for(let end = 0; end < nums.length; end++) {
// 开始遍历,即移动窗口终止位置,放大窗口
// 计算当前窗口内元素的和
sum += nums[end]
// 当sum >= target时 , 窗口内有符合要求的数组,存储子数组长度,并开始移动起始位置
while(sum >= target){
// 计算出此时子窗口内数组的长度
subLen = end - start + 1
// 比较此时子数组长度和result,取小
result = result > subLen ? subLen : result
// 子数组和减去当前起始位置的值
sum -= nums[start]
// 开始移动窗口起始位置,即缩小窗口
start++
}
}
// 最后判断如果result > 原数组长度,则说明没有最小子数组返回长度0,反之返回result
return result > nums.length ? 0 : result
};
// @lc code=end
-
复杂度分析
- 时间复杂度:
O(n)。n为nums数组的长度,只有一层for循环遍历了nums的长度。 - 空间复杂度:
O(1)。只使用了sum、result、subLen、start常数个变量。
- 时间复杂度: