wengjq / Basics

前端基础知识

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

如何实现一个栈的方法,它能够返回栈的最小值且时间复杂度为O(1)

wengjq opened this issue · comments

push 和 pop 操作很明显就是 O(1)的时间复杂度,关键是 min 函数,一般来说,我们求栈中的最小值,会从栈顶开始遍历栈,并设置一个变量 Min 来保存每次遍历时的最小值 ,遍历到比 Min 还小的元素,就将该元素赋给 Min,但这种方法的时间复杂度为 O(n)。

思路一:每次入栈和出栈同时操作两个元素,下面的元素是需要入栈的元素,上面的元素是整个栈的最小元素。

function Stack() {
  this.items = [];
}

Stack.prototype = {
  constructor: Stack,
  add: function (element) {
    //如果数组内没有元素,则最小元素就是入栈的元素
    if (!this.items.length) {
      this.items.push(element);
      this.items.push(element);
    } else {
      //获取当前最小元素
      var minElement = this.getMinElement();

      if (element < minElement) {
        minElement = element;
      }

      this.items.push(element);
      this.items.push(minElement);
    }
  },
  //实现出栈的方法
  remove: function () {
    this.items.pop();
    return this.items.pop();
  },
  //获取栈的最小值的方法
  getMinElement: function () {
    if (!this.items.length) {
      return null;
    } else {
      return this.items[this.items.length - 1];
    }
  }
}

思路二:同时维护两个栈,一个用来存储元素,另一个来存储最小值的下标。两个栈同步更新,这样就能实现获取最小值的功能。

function Stack() {
  this.items = []; // 栈 A ,存储元素
  this.minItemsSubscript = []; // 栈 B ,存储栈 A 元素最小值下标
}

Stack.prototype = {
  constructor: Stack,
  add: function (element) {
    // 当第一个元素进入栈 A 的时候,让新元素的下标进入栈 B 。这个唯一的元素是栈 A 的当前最小值
    if (!this.items.length) {
      this.items.push(element);
      this.minItemsSubscript.push(0);
    } else {
    // 每当新元素进入栈 A 时,比较新元素和栈 A 当前最小值的大小,如果小于栈 A 当前最小值,则让新元素的下标进入栈 B ,此时栈 B 的栈顶元素就是栈 A 当前最小值的下标
      var minElement = this.getMinElement();

      if (element < minElement) {
        this.minItemsSubscript.push(this.items.length);
      }

      this.items.push(element);
    }
  },
  // 每当栈 A 有元素出栈时,如果出栈元素是栈 A 当前最小值,则让栈 B 的栈顶元素也出栈。此时栈 B 余下的栈顶元素所指向的,是栈 A 当中原本第二小的元素,代替刚才的出栈元素成为了栈 A 的当前最小值。(备胎转正)
  remove: function () {
    var minElement = this.getMinElement();
    var popItem = this.items.pop();

    if (popItem === minElement) {
      this.minItemsSubscript.pop();
    }
    return popItem;
  },
  // 直接返回栈 B 的栈顶所指向的栈 A 对应元素
  getMinElement: function () {
    if (!this.items.length || !this.minItemsSubscript.length) {
      return null;
    } else {
      return this.items[this.minItemsSubscript[this.minItemsSubscript.length - 1]];
    }
  }
}