场景
- 当遇到滑动窗口场景时,通过双端队列能过迅速找到最值
实现过程
- 定义双端队列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];
const index = this.queue.findIndex((i) => this.arr[i] <= arrNum);
if (index === -1) {
this.queue.push(this.right);
} else {
this.queue[index] = this.right;
this.queue.length = index + 1;
}
}
}
moveOneLeftStep() {
if (this.left < this.right) {
this.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();
console.log("双端队列索引值", q.getWindow());
console.log("范围", q.getRange());