滑动窗口问题总结

问题描述

在处理数组(或 LinkedList)的许多问题中,我们被要求在给定大小的所有子数组(或子列表)中查找或计算某些东西。例如,看看这个问题:

给定一个数组,求其中所有“K”个连续元素的子数组的平均值。

让我们用一个真实的输入来理解这个问题:

Array: [1, 3, 2, 6, -1, 4, 1, 8, 2], K=5

在这里,我们被要求找到给定数组中“5”个连续元素的所有子数组的平均值。让我们解决这个问题:
对于前 5 个数字(索引 0-4 的子数组),平均值为:(1 + 3 + 2 + 6-1) / 5 => 2.2
接下来 5 个数字(索引 1-5 的子数组)的平均值为:(3 + 2 + 6-1 + 4) / 5 => 2.8
对于接下来的 5 个数字(索引 2-6 的子数组),平均值为:(2 + 6-1 + 4 + 1) / 5 => 2.4

这是包含所有大小为 5 的子数组的平均值的最终输出:

Output: [2.2, 2.8, 2.4, 3.6, 2.8]

若我们暴力算法将计算给定数组的每个 5 元素子数组的总和,并将总和除以“5”以求平均值。
时间复杂度:由于对于输入数组的每个元素,我们都在计算其下一个“K”个元素的总和,因此上述算法的时间复杂度将为 O (N * K)
O (N * K),其中“N”是输入数组中的元素数。

我们能找到更好的解决方案吗?您是否发现上述方法效率低下?

效率低下的是,对于任何两个大小为“5”的连续子数组,重叠部分(将包含四个元素)将被计算两次。例如,采用上述输入:在这里插入图片描述
如你所见,子数组(索引从 0-4)和子数组(索引从 1-5)之间有四个重叠元素。我们可以以某种方式重用我们为重叠元素计算的总和吗?

解决此问题的有效方法是将每个子数组可视化为“5”个元素的滑动窗口。这意味着当我们移动到下一个子数组时,我们将窗口滑动一个元素。重用前一个子数组的总和这将使我们免于遍历整个子数组来求和,因此,算法复杂度将降低到 O (N)。
在这里插入图片描述
这是滑动窗口方法最基本的解题模板:

int slidingwindow(int K,  vector<int>& arr) {
    vector<double> result(arr.size() - K + 1);
    int windowSum = 0;
    int windowStart = 0;//窗口的头部
    for (int windowEnd = 0; windowEnd < arr.size(); windowEnd++) {
      if ()//关键在于窗口收缩的时机,判断逻辑while或者if
       {//窗口收缩一般是指窗口头部向前移动,此时要更新与窗口头部相关的数据结构如map等}
    }
    return result;
  }

问题的关键

1.本类问题的代码关键是根据题目得出窗口收缩的时机,以及想清楚窗口收缩后应该干什么
2.窗口的增大一般是用for循环来向后走
3.同时也要考虑需不需要其他数据结构辅助保存一些需要的数据

后面列出几个典型问题,并指出问题的核心
简单问题
中等问题
难题
更难的题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值