双端队列最值结构

文章目录

  • 场景
  • 实现过程
  • 示例

场景

  • 当遇到滑动窗口场景时,通过双端队列能过迅速找到最值

实现过程

  • 定义双端队列left和right边界,双端队列只存储元素的索引,因为存储索引可以映射到值,比单纯存值具有更多的信息
  • 移动right
    • 初始第一个数值直接放入队列中,后续移动过程中,如果比当前队列中元素都小,直接将对应索引放入队列末尾,否则插入队列中比它小的元素前面(如果值相等,则判断索引更大的在前面),然后删除掉它之后的所有元素(保证索引连续,使得移动left时能放心删除)
  • 移动left
    • 更新双端队列左边界,如果left比队列中的首元素索引要大了,说明当前元素已经不在left和right范围内了,直接弹出删除掉该元素,这也是为什么移动right过程中需要删除掉比插入元素小的所有元素,因为能够保证索引一直是增序,确保删除掉元素后,其他元素一定是在left和right范围内

示例

class Queue {
  arr = [];
  queue = [];
  left = 0;
  right = 0;
  constructor(arr) {
    this.arr = arr;
    this.queue[0] = 0;
  }
  moveOneRightStep() {
    if (this.right < this.arr.length - 1) {
      this.right++;

      const arrNum = this.arr[this.right];
      // 找到第一个比当前 num 小的 queue 中的值
      // 这里也可以 while 每找一个 pop 掉一个
      const index = this.queue.findIndex((i) => this.arr[i] <= arrNum);

      if (index === -1) {
        this.queue.push(this.right);
      } else {
        // 存入当前 num,并删除掉比 num 小的所有值
        this.queue[index] = this.right;
        this.queue.length = index + 1;
      }
    }
  }
  moveOneLeftStep() {
    if (this.left < this.right) {
      this.left++;
      // 移动left,删除掉过期的最大值
      if (this.left > this.queue[0]) {
        this.queue.shift();
      }
    }
  }

  getWindow() {
    return this.queue;
  }

  getRange() {
    return [this.left, this.right];
  }
}

const arr = [5, 2, 3, 7, 4, 5];
const q = new Queue(arr);

q.moveOneRightStep();
q.moveOneRightStep();
q.moveOneRightStep();
q.moveOneRightStep();
q.moveOneRightStep();

q.moveOneLeftStep();
q.moveOneLeftStep();
q.moveOneLeftStep();
// q.moveOneLeftStep();
// q.moveOneLeftStep();

console.log("双端队列索引值", q.getWindow());
console.log("范围", q.getRange());

你可能感兴趣的:(前端算法,javascript,前端)