滑动窗口
讲解视频(更重要):拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili
文章讲解:代码随想录 (programmercarl.com)
拓展题目:904、76
与双指针思路一样,用两个指针进行操作。只不过是取两个指针中间的集合,更像一个正在滑动的窗口。
思路:
用一个for循环实现两个for循环所做的事情,而这个for循环的迭代指针j表示的是滑动窗口的终止位置,起始位置则需要用动态移动的策略来确定。滑动窗口的核心:如何移动起始位置。
当终止位置j固定时:若窗口里的元素和大于等于target,说明这是符合条件的一个窗口,在获得窗口长度后,起始位置就可以向后移动来缩小目前的窗口,来看下一个窗口是否符合条件。–这样,我们就可以动态地调整起始位置,来去收集不同长度窗口里的和。
!!!!题目过程及示意图:
- j不断右移,直到i和j之间的元素和sum>=target,j停下;
- 此时sum>=target,不断右移i,每右移一次更新一次长度;此时sum不断减小,直到sum<target;
- 然后j不断右移,每次右移都更新sum,直到sum>=target,j停下;继续重复步骤(2)(3)。
- tips:表示无穷大用
int res = INT32_MAX;
int main() { int target = 7, nums[6] = { 2,3,1,2,4,3 }; int len = sizeof(nums) / sizeof(nums[0]); int sum = 0;//滑动窗口内元素的和 int res = INT32_MAX;//记录最短子序列的长度,初始化为无穷大 int i = 0;//!滑动窗口的起始位置 for (int j = 0; j < len; ++j) {//!!滑动窗口的终止位置j sum += nums[j];//!!终止位置每向后移动一位,就将该值加入。固定终止位置j。 //下方while是起始位置i的移动 while (sum >= target) {//!!若滑动窗口里的元素和大于等于target,说明符合要求,就可以不断向后移动起始位置来缩小窗口,直到窗口和小于target int subL = j - i + 1;//!更新滑动窗口大小 res = min(res, subL);//!若当前窗口大小比最小窗口还小,则更新 sum -= nums[i++];//!!向后移动起始位置,并更新窗口内的元素和 } //!!!每次固定终止位置j时,若窗口元素和大于target,起始位置i都会不断向后移动,直到窗口元素和小于target,停在第一个不成立的元素位置。通过终止位置j的后移来增大滑动窗口元素和,直到大于target才能再次移动起始位置i。 } res = res == INT32_MAX ? 0 : res;//若不存在符合条件的子数组,返回0 cout << res; return 0; }
空间复杂度O(1),时间复杂度O(2n):不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 。