zl程序教程

您现在的位置是:首页 >  其他

当前栏目

辛辣天塞!滑动窗口之【和的最大值】&【最大值集合】

amp集合 窗口 最大值 滑动
2023-06-13 09:12:48 时间

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

本篇带来两道经典的关于滑动窗口的算法题,有兴趣可在控制台跑一跑~

求和的最大值

题目来源:上一篇掘文《温故知新 —— Sliding Window》

比如给定如下数组:[ 5, 7, 1, 4, 3, 6, 2, 9, 2 ],求出 5 个连续元素的最大和是多少? [5, 7, 1, 4, 3] 是第一组 5 个连续元素,求和是 20[7, 1, 4, 3, 6] 是第二组 5 个连续元素,求和是 21......这样一直进行下去,最终对比发现 5 个连续元素的最大和是 24,由 [4, 3, 6, 2, 9] 组成;

这里给出本瓜的另一种写法,仅供参考:

var maxSlidingWindow = function(nums, k) {
   const sum = function (arr) {
        return arr.reduce(function(prev, curr, idx, arr){
            return prev + curr;
        });
    };
    let slidingWindow=nums.slice(0,k)
    let newSlidingWindow=[]
    let maxVal;
    for(let i=k;i<nums.length;i++){
        newSlidingWindow=slidingWindow.slice(1).concat(nums[i])
        maxVal=Math.max(sum(slidingWindow),sum(newSlidingWindow))
        slidingWindow = newSlidingWindow
    }
    return maxVal
};
const nums= [ 5, 7, 1, 4, 3, 6, 2, 9, 2 ]
const k=5
maxSlidingWindow(nums,k) // 24

求最大值集合

题目来源:leetcode-239 (复杂)

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

本题在力扣中,难度被标为:复杂,这复杂吗?

  1. 写一个函数来判断数组中最大的数;
  2. 初始化窗口,求最大值保存;
  3. 滑动窗口,再求最大值保存;
  4. 滑动直至完毕;

本瓜题解:

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var maxSlidingWindow = function(nums, k) {
  if(k===1) return nums; // 特殊情况
  let slidingWindow = nums.slice(0,k)
  let newSlidingWindow = []
  let resArr = []
  resArr.push(Math.max(...slidingWindow))
  for(let i=k;i<nums.length;i++){
      newSlidingWindow = slidingWindow.slice(1).concat(nums[i])
      resArr.push(Math.max(...newSlidingWindow))
      slidingWindow = newSlidingWindow
  }
  return resArr
};

结果,当数组长度为 10 w 时,报错 超出时间限制

噢!用 Math.max() 来每次从窗口找最大值,时间复杂度是 O(n * k),仍然很大;

窗口固定,求最大值集合 在根本上是 单调队列 的问题!

本瓜录屏了一个非常棒的动画效果解释:

最后 JS 题解:

var maxSlidingWindow = function (nums, k) {
  // 队列数组(存放的是元素下标,为了取值方便)
  const q = [];
  // 结果数组
  const ans = [];
  for (let i = 0; i < nums.length; i++) {
    // 若队列不为空,且当前元素大于等于队尾所存下标的元素,则弹出队尾
    while (q.length &amp;&amp; nums[i] >= nums[q[q.length - 1]]) {
      q.pop();
    }
    // 入队当前元素下标
    q.push(i);
    // 判断当前最大值(即队首元素)是否在窗口中,若不在便将其出队
    while (q[0] <= i - k) {
      q.shift();
    }
    // 当达到窗口大小时便开始向结果中添加数据
    if (i >= k - 1) ans.push(nums[q[0]]);
  }
  return ans;
};

实际上,滑动窗口还是有很多扩展的空间,即使是窗口滑动,怎么滑,滑动后怎么做,里面就存在很大的解题思路的差异!

以上。

我是掘金安东尼,公众号同名,输出暴露输入,技术洞见生活,下次再会~~