如何实现一个包含min函数的栈

547 阅读2分钟

题目: 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3
minStack.pop();
minStack.top();   --> 返回 0
minStack.min();   --> 返回 -2

难点

  1. push 和 pop 的操作时间复杂度是 O(1), min 函数如果使用排序或查找实现, 时间复杂度是 O(n), 无法完成题目要求 O(1)
  2. 定义一个 minValue 保存最小值, 每次 push 时, 和 minValue 比较, 保证 minValue 一直是最小元素, 调用 min 函数的时候返回 minValue 的值。 但是如果 pop 出去的值刚好就是最小值, 再次调用 min 的时候就无法知道次最小值是多少了。

思路

可以通过两个栈来实现, 一个主栈用来存储数据结构, 一个辅助栈用来存储最小值。

  • 当主栈元素入栈时, 辅栈存储栈中元素的最小值
  • 当主栈元素出栈时, 辅栈元素也出栈
  • 最小值就是辅栈元素的顶部值
  • 栈顶值就是主栈元素的顶部值

代码

class Stack {
    constructor() {
        this.arr = []
    }

    add(value) {
        this.arr.push(value)
    }

    pop() {
        return this.arr.pop()
    }

    top() {
        const len = this.arr.length;
        if(len != 0) {
            return this.arr[len - 1]
        }
    }
    empty() {
        return this.arr.length === 0
    }
}

class MinStack {
    constructor() {
        this.A = new Stack()   // 主栈
        this.B = new Stack()   // 辅栈
    }

    push(value) {
        this.A.add(value)
        if(this.B.empty()) {
            this.B.add(value)
        }else{
            this.B.add(value < this.B.top() ? value : this.B.top())
        }
    }

    min() {
        return this.B.top()   ///返回栈最小值
    }

    pop() {
        this.B.pop()
        return this.A.pop()    
    }

    top() {
        return this.A.top()   //返回栈顶值
    }
}

const minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
console.log(minStack.min());   //返回 -3
minStack.pop();
console.log(minStack.top());   //返回 0
console.log(minStack.min());   //返回 -2

总结

本篇我们学习了如何实现一个自带 min 函数的栈, min 函数的时间复杂度为 O(1)

利用主栈和辅栈实现 min, 主栈存储数据结构,辅栈存储最小值,主栈和辅栈同时入栈和出栈,保持栈的同步,主栈的 top 是栈的顶值, 辅栈的 top 是栈的最小值。

思考

通过辅栈的方式, min 的时间复杂度为 O(1) 达到了解题要求, 但是辅栈内部有很多连续重复的元素,会额外占用一份主站的空间, 辅栈的存储是否可以优化呢?

可以

  • 入栈时,辅栈只存储比辅栈栈顶小的值
  • 出栈时,主栈 pop, 如果最小值被 pop了, 辅栈也要和主栈同步, 把最小值 pop 了。
class MinStack {
    push(value) {
        this.A.add(value)
        if(this.B.empty() || value <= this.B.top()) {
            this.B.add(value)
        }
    }
    pop() {
        if(this.A.pop() === this.B.top()) {
            this.B.pop()
        }
    }
}