【算法】滑动窗口1—窗口大小固定
一、定义
滑动窗口算法(Sliding Window Algorithm)是一种用于解决数组或字符串中子数组或子串问题的优化技术。它通过维护一个窗口(通常是数组或字符串的一个连续子区间),在遍历过程中动态调整窗口的起始和结束位置,从而高效地解决问题。
滑动窗口的核心思想是:
窗口大小固定:窗口的大小在滑动过程中保持不变。
窗口大小可变:窗口的大小根据条件动态调整。
二、使用场景
滑动窗口算法通常用于以下场景:
1.子数组/子串问题:
求满足条件的最大或最小子数组/子串。
例如:最大子数组和、最小覆盖子串、最长无重复字符子串等。
2.固定窗口大小问题:
例如:计算大小为
k
的子数组的平均值。3.优化暴力解法:
将时间复杂度从
O(n²)
优化到O(n)
。
三、示例
1.例题1:固定窗口大小
【题目描述】给定一个数组和一个整数 k
,计算所有大小为 k
的子数组的平均值。
【题目分析】
(1) 什么是子数组?
子数组是数组中连续的一段元素。
例如,数组
[1, 3, 2, 6, -1]
的子数组包括[1, 3, 2]
、[3, 2, 6]
等。
(2)什么是大小为 k
的子数组?
大小为
k
的子数组是指长度为k
的连续子数组。例如,如果
k = 3
,那么子数组的长度必须是 3。
(3)什么是子数组的平均值?
子数组的平均值是指子数组中所有元素的和除以子数组的长度。
例如,子数组
[1, 3, 2]
的平均值是(1 + 3 + 2) / 3 = 2
。
(4)问题的目标
对于数组中的每一个大小为
k
的子数组,计算其平均值,并返回所有平均值的集合。
【解题思路】
(1)暴力解法
遍历数组,对于每一个起始位置
i
,计算从i
到i + k - 1
的子数组的和,然后除以k
得到平均值。时间复杂度:
O(n * k)
,其中n
是数组的长度。
(2)滑动窗口优化
使用滑动窗口技术,避免重复计算子数组的和。
初始化第一个窗口的和,然后在滑动窗口时,加上新元素,减去旧元素。
时间复杂度:
O(n)
。
#include <iostream> using namespace std; void sw(int nums[], int n, int k) { if (n < k) return; // 如果数组长度小于k,直接返回 double windowSum = 0; // 初始化窗口 for (int i = 0; i < k; i++) { windowSum += nums[i]; } cout << windowSum / k << " "; // 滑动窗口 for (int i = k; i < n; i++) { windowSum += nums[i] - nums[i - k]; // 加上新元素,减去旧元素 cout << windowSum / k << " "; } cout << endl; } int main() { int nums[] = {1, 3, 2, 6, -1, 4, 1, 8, 2}; int n = sizeof(nums) / sizeof(nums[0]); int k = 5; sw(nums, n, k); return 0; }
【过程解释】
初始化窗口:
计算第一个窗口的和
windowSum
,即nums[0]
到nums[k-1]
的和。输出第一个窗口的平均值
windowSum / k
。滑动窗口:
从第
k
个元素开始,滑动窗口。每次滑动时,加上新元素
nums[i]
,减去旧元素nums[i - k]
。输出当前窗口的平均值
windowSum / k
。
图示:
第一次:(1+3+2)/3
第二次:(3+2+6)/3 ,对比上一次,少了第一个数1,多了后一个数6
第二次:(2+6-1)/3 ,对比上一次,少了上一个数2,多了后一个数-1
扫描二维码推送至手机访问。
版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。