大三寒假要结束了,继续备战秋招,年前刷了些双指针、数组、链表的简单LeetCode题,都没有做笔记,现在也忘得差不多了,计划写一份专栏记录刷题的过程,复盘算法中的细节,由易到难,先刷简单题,再斩中等题!
一转眼就到4月份了,投递了好多暑期实习,4月份笔面试就会陆续开启,距离秋招也越来越近,这段时间在刷LeetCode Hot 100,每天刷个两道mid题,同时作个笔记,作为复盘,也作为到时笔面试前的复习资料
目录
一、关键思路:双指针-滑动窗口法
滑动窗口法是一种常用的算法技巧,它通常用于数组或字符串的遍历,以及子串或子序列的搜索等问题。该算法的基本思想是维护一个滑动窗口,每次移动窗口,通过更新窗口的左右边界,来得到新的结果。具体来说,滑动窗口算法通常包含以下几个步骤:
- 初始化窗口左右边界,例如 left=0, right=0。
- 移动右边界,直到满足某个条件,例如窗口内元素的和等于目标值。
- 移动左边界,直到不满足条件,同时更新结果,例如记录最小窗口长度。
- 重复步骤 2 和步骤 3,直到右边界到达数组或字符串的末尾。
二、滑动窗口法优点
滑动窗口算法的优点包括:
- 时间复杂度较低:滑动窗口算法通常只需要遍历一次数组或字符串,因此时间复杂度为 O(n)。
- 空间复杂度较低:滑动窗口算法通常只需要维护常数个变量,因此空间复杂度为 O(1)。
- 可扩展性强:滑动窗口算法通常可以很容易地扩展到多维数组或多个字符串的问题中。
- 可读性强:滑动窗口算法的思路简单,代码实现也比较容易理解。
三、例题训练
3.1 209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-size-subarray-sum
- 实现思路:
具体实现时,我们可以用两个指针来表示滑动窗口的左右端点,
1. 初始化时两个指针都指向数组的起始位置;
2. 然后,我们不断移动右指针,直到子数组的和大于等于 target,此时更新答案;
3. 然后移动左指针,缩小子数组的范围,直到子数组的和小于 target;
4. 然后再移动右指针,重复这个过程,直到右指针移动到数组的末尾。
时间复杂度为O(n),其中n为数组的长度。因为每个元素最多被访问两次,一次是被右指针访问到,一次是被左指针访问到。空间复杂度为O(1),因为我们只需要维护常数个变量。
- 核心思路:
每一轮迭代,将 nums[right] 加到 sum,如果 sum > target,则更新子数组的最小长度 (此时子数组的长度是right- left+1),然后将nums[left] 从 sum中减去并将 left右移,直到 sum< target,在过程中同样更新了数组的最小长度。在每一轮迭代的最后,将 right右移
for(int right=0;right<len;right++)
{
res+=nums[right];
while(res>=target)
{
int curlen=right-left+1;
minlen = curlen<minlen?curlen:minlen;
res-=nums[left++];
}
}
- C++代码实现:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int res=0;
int minlen=INT32_MAX;
int left=0;
int len =nums.size();
for(int right=0;right<len;right++)
{
res+=nums[right];
while(res>=target)
{
int curlen=right-left+1;
minlen = curlen<minlen?curlen:minlen;
res-=nums[left++];
}
}
return minlen == INT32_MAX ? 0 : minlen;
}
};