用 JavaScript 创建一个栈,并优化时间复杂度 (附 Python 描述)

本文介绍了一种在常数时间内支持push、pop、top及获取最小元素的栈实现方法。通过维护两个数组,分别存储数据和当前最小值,优化getMin操作至O(1)时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

Design a stack that supports push, pop, top, and retrieving the
minimum element in constant time.

要实现的栈方法

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
getMin() – Retrieve the minimum element in the stack.


两种解法

方法一

先想到的第一种方法如下:

  • 用一个数组保存数据
  • pushpoptop 方法都唾手可得
  • getMin 方法要获取最小值,就遍历数组,找到最小值并返回

由于 getMin 方法中的一次 for 循环,时间复杂度为 O(n)。
这里存在优化的空间。

var MinStack = function () {
  this.stack = []
}

MinStack.prototype.push = function (x) {
  this.stack.push(x)
}

MinStack.prototype.pop = function () {
  this.stack.pop()
}

MinStack.prototype.top = function () {
  let len = this.stack.length
  if (len > 0) {
    return this.stack[len - 1]
  }
}

MinStack.prototype.getMin = function () {
  let stack = this.stack
  let tempMin = stack[0]
  for (let i = 1; i < stack.length; i++) {
    if (tempMin > stack[i]) {
      tempMin = stack[i]
    }
  }
  return tempMin
}

方法二

核心思路:
用另一个数组保存每个新元素入栈时,当时的最小值。

  • push pop 方法中多维护一个 min 数组
  • getMin 时,只需要取 min 数组最后一位即可
  • 由于省去了 for 循环,时间复杂度将为常数阶 O(1)

照这个思路有了第一版代码如下

var MinStack = function () {
  this.stack = []
  this.min = []
}

MinStack.prototype.push = function (x) {
  this.stack.push(x)
  let min = this.min[this.min.length - 1]
  if (min !== undefined) {
    min > x ? this.min.push(x) : this.min.push(min)
  } else {
    this.min.push(x)
  }
}

MinStack.prototype.pop = function () {
  this.stack.pop()
  this.min.pop()
}

MinStack.prototype.top = function () {
  let len = this.stack.length
  if (len > 0) {
    return this.stack[len - 1]
  }
}

MinStack.prototype.getMin = function () {
  let len = this.min.length
  if (len > 0) {
    return this.min[len - 1]
  }
}

容易发现,push 方法中,取得之前最小值的操作与 getMin 方法存在重复,本着 DRY (do not repeat youself)的原则,修改 push 如下

方法二代码

var MinStack = function () {
  this.stack = []
  this.min = []
}

MinStack.prototype.push = function (x) {
  let preMin = this.getMin()
  if (preMin !== undefined) {
    preMin > x ? this.min.push(x) : this.min.push(preMin)
  } else {
    this.min.push(x)
  }
  this.stack.push(x)
}

MinStack.prototype.pop = function () {
  this.stack.pop()
  this.min.pop()
}

MinStack.prototype.top = function () {
  let len = this.stack.length
  if (len > 0) {
    return this.stack[len - 1]
  }
}

MinStack.prototype.getMin = function () {
  let len = this.min.length
  if (len > 0) {
    return this.min[len - 1]
  }
}

性能对比

两种方法运行时间对比如下(JavaScript),可见速度有了明显提升。

性能对比

对应的 Python 描述如下

方法一

class MinStack(object):

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        

    def push(self, x):
        """
        :type x: int
        :rtype: void
        """
        self.stack.append(x)
        

    def pop(self):
        """
        :rtype: void
        """
        self.stack.pop()

    def top(self):
        """
        :rtype: int
        """
        return self.stack[-1]
        

    def getMin(self):
        """
        :rtype: int
        """
        return min(self.stack)

方法二

class MinStack(object):

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.min = []
        

    def push(self, x):
        """
        :type x: int
        :rtype: void
        """
        self.stack.append(x)
        if(len(self.min) > 0):
            self.min.append(min([x, self.min[-1]]))
        else:
            self.min.append(x)
        

    def pop(self):
        """
        :rtype: void
        """
        self.stack.pop()
        self.min.pop()

    def top(self):
        """
        :rtype: int
        """
        return self.stack[-1]
        

    def getMin(self):
        """
        :rtype: int
        """
        return self.min[-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值