功能说明
MinStack 在普通后进先出栈的基础上支持 O(1) 的 min 查询。每次 push 时同步记录到当前位置为止的最小值,pop 时两个栈一起弹出,因此栈顶的最小值始终对应当前元素范围。适合滑动窗口、股票价格、撤销历史以及需要实时最小值的编辑器状态等场景。peek、pop、size 与 toArray 提供常规栈操作。
关键代码
内部使用两个原生数组,values 保存元素,minimums 保存前缀最小值。push 时取当前最小值与新区比较,空栈时以 Infinity 作为初始值,保证第一个元素成为最小值。pop 同时弹出两个数组,空栈返回 undefined 而不抛错。min 在空栈时返回 undefined,因为数组末位不存在。元素必须是有限数字,NaN 被拒绝以避免比较失效。
使用注意
最小值栈占用与元素数量相同的额外空间,若数据量极大且只需偶尔查询,可改用稀疏记录或分段最小值。Infinity 只是内部哨兵,不会被返回,除非显式 push 了 Infinity。该结构不支持删除中间元素,遇到需要撤销任意位置的操作应换用其他数据结构。pop 的 undefined 返回值与真实 undefined 元素无法区分,但类型校验已禁止 undefined 入栈。
验证方式
依次 push 3、1、2,断言 min 为 1,pop 后 min 仍为 1,再 pop 后 min 为 3。测试重复最小值、递增序列、递减序列和空栈的 peek、pop、min。验证 size 随操作变化、toArray 不暴露内部数组。最后测试字符串、NaN、undefined 入栈会抛错,并确认链式 push 返回实例本身。
代码示例
export class MinStack {
#values = [];
#minimums = [];
push(value) {
if (typeof value !== "number" || Number.isNaN(value)) {
throw new TypeError("value must be a number");
}
this.#values.push(value);
const currentMin = this.#minimums.length > 0
? this.#minimums[this.#minimums.length - 1]
: Infinity;
this.#minimums.push(Math.min(value, currentMin));
return this;
}
pop() {
if (this.#values.length === 0) return undefined;
this.#minimums.pop();
return this.#values.pop();
}
peek() {
return this.#values[this.#values.length - 1];
}
min() {
return this.#minimums[this.#minimums.length - 1];
}
get size() {
return this.#values.length;
}
toArray() {
return [...this.#values];
}
}