leetcode:239.滑动窗口最大值(JavaScript)

239. 滑动窗口最大值

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

返回 滑动窗口中的最大值

示例 1:

输入: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

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

最初的想法是模拟窗口向右移,每次对窗口内元素进行排序,取最大的数。超时了。

var maxSlidingWindow = function(nums, k) {
    let res = [], que = [];
    for (let i = 0; i <= nums.length; i++) {
        if (i < k) {
            // 维持窗口长度为k
            que.push(nums[i]);
        } else {
            // 深拷贝
            let tem = [...que];
            // 排序
            tem.sort((a, b) => a - b);
            // 记录将当前窗口中最大值
            res.push(tem[k - 1]);
            // 删除当前窗口最左边的数
            que.shift();
            // 当前窗口向右移一位
            que.push(nums[i]);
        }
    }
    return res;
};

后边看题解后,可以用单调队列(单调队列:从头到尾单调递增或递减)做,维持一个单调递减的队列,队头总是当前窗口最大的值。

对于如何维持一个单调队列,代码中有详细注释,下面模拟过程

单调队列示例:[8, 5, 2, 1]
维护过程:[8, 5, 2, 1], 要添加的新元素 4
第一次:4 > 1, 删除队尾元素删除,操作后队列:[8, 5, 2]
第二次:4 > 2, 删除队尾元素删除,操作后队列:[8, 5]
第三次:4 < 5, 将4添加到队尾,操作后队列:[8, 5, 4];

你会发现队列的长度并不是一定总是等于k,但是注意

  // 如果对头元素时上一个窗口值得开头就弹出,更新对列头
if (que[0] === nums[start++])
  	que.shift();

这一段代码判断如何更新队头值得好好想一想,它可以保证既是队列长度小于等于k,也能取得正确的数存入结果数组。

完整代码

var maxSlidingWindow = function (nums, k) {
  let res = [], que = [], start = 0, i = 0;
  while (i < k) {
      // 初始化长度为k的窗口
    add(que, nums[i++]);
  }
  while (i <= nums.length) {
      // 记录当前窗口最大值
    res.push(que[0]);
      // 更新当前窗口
    add(que, nums[i]);
      // 如果对头元素时上一个窗口值得开头就弹出,更新对列头
    if (que[0] === nums[start++])
      que.shift();
    i++;
  }
  return res;
};
// 维持单调队列
function add(que, value) {
    // 将要加入的新元素从队尾开始与元素比较
    let back = que[que.length - 1];
    // 若队尾元素比当前元素小就将队尾元素从队列中删除
    while (back !== undefined && back < value) {
         // 更新队尾元素
      que.pop();
      back = que[que.length - 1];
    }
    // 将新元素加入队列
    que.push(value);
}

如果还有小伙伴不懂可以去看看代码随想录,那里有更加详细的解题过程哦!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值