返回

向解题新模式飞奔吧!—— LeetCode 239,滑动窗口的最大值

前端

大展身手:以扩展运算符和最大值子数组寻找答案

面对这道颇具挑战性的算法题,扩展运算符就如一把锋利的长剑,为我们斩断了前进的荆棘。它可以将滑动窗口内的所有元素轻松提取出来,化为一个个单独的战士,任由我们调度。同时,最大值子数组这个概念也如一盏明灯,指引我们找到滑动窗口中那个至高无上的王者。

// 引入扩展运算符,准备在数组上大展身手
const nums = [1, 3, -1, -3, 5, 3, 6, 7];
const k = 3;

// 准备就绪,将滑动窗口内的元素轻松提取出来
const slidingWindow = nums.slice(0, k);

// 巧妙利用扩展运算符,化零为整
const maxSubArray = Math.max(...slidingWindow);

// 开启循环,让滑动窗口稳步前行
for (let i = k; i < nums.length; i++) {

  // 踢出老兵,纳入新兵
  slidingWindow.shift();
  slidingWindow.push(nums[i]);

  // 用最大值子数组理论,不断更新最大值
  maxSubArray = Math.max(maxSubArray, Math.max(...slidingWindow));

}

// 胜利在望,将答案高声报出
console.log(`滑动窗口中的最大值是:${maxSubArray}`);

剑走偏锋:单调队列横空出世

就在你为扩展运算符和最大值子数组的完美组合沾沾自喜时,另一种解法横空出世——单调队列。它巧妙地避开了最大值子数组的计算,转而用一种更加简洁优雅的方式找到了滑动窗口中的最大值。

// 引入单调队列,开启别具一格的解题之旅
const nums = [1, 3, -1, -3, 5, 3, 6, 7];
const k = 3;

// 初始化单调队列,为我们的冒险做好准备
const monoQueue = [];

// 开始循环,让滑动窗口动起来
for (let i = 0; i < nums.length; i++) {

  // 队列的前面如果有比当前值小的元素,就通通剔除掉
  while (monoQueue.length > 0 && nums[monoQueue[monoQueue.length - 1]] < nums[i]) {
    monoQueue.pop();
  }

  // 将当前值添加到队列的尾部
  monoQueue.push(i);

  // 如果队首元素已经不属于当前的滑动窗口,就将其移除
  if (monoQueue[0] <= i - k) {
    monoQueue.shift();
  }

  // 滑动窗口中的最大值就是队列首部的元素,简单明了
  const maxInWindow = nums[monoQueue[0]];

  // 将答案收入囊中,为下一次胜利做好准备
  console.log(`滑动窗口中的最大值是:${maxInWindow}`);

}

拨开迷雾,直指核心

无论你选择扩展运算符和最大值子数组的组合,还是剑走偏锋的单调队列,这些方法的本质都是相同的——它们都在不断地寻找滑动窗口内的最大值。扩展运算符和最大值子数组的方法就像是用一把重剑,劈开前方的荆棘;而单调队列就像是一柄利刃,以迅捷的速度刺穿障碍。

这道题的意义,不在于哪种方法更好,而在于让我们认识到算法世界里的多种可能性。我们应该不断磨砺自己的解题能力,掌握不同的方法,以应对千变万化的挑战。

终点线上的思考

当你读完这篇文章,希望你已经对 LeetCode 239 题有了更深的理解。算法与编程的世界里,总会有新的挑战等待着我们,愿我们都能在不懈的探索中,不断进步,不断超越自我。