Leetcode 演算法題解系列 - 最小棧

安歌發表於2022-01-22

本專題旨在分享刷Leecode過程發現的一些思路有趣或者有價值的題目。【當然,是基於js進行解答】。

題目相關

  • 原題地址
  • 題目描述:

    定義棧的資料結構,請在該型別中實現一個能夠得到棧的最小元素的 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.
    
    // 解題框架如下
    var MinStack = function() {};
    MinStack.prototype.push = function(x) {};
    MinStack.prototype.pop = function() {};
    MinStack.prototype.top = function() {};
    MinStack.prototype.min = function() {};
    
    // 實際呼叫示例 
    // var obj = new MinStack()
    // obj.push(x)

思路解析

  • 首先,粗看一下pushpop方法實現比較簡單,可以用js陣列原生的相關方法進行實現;
  • 其次,top方法只要返回棧頂元素, 也就是陣列末位元素,也比較簡單;
  • 接著,min方法需要獲取最小值,並且要求時間複雜度都是 O(1),這就意味著我們在min方法中,不能去遍歷陣列,必須想辦法提前儲存;而且在pushpop過程,需要更新儲存的最小值。

那麼到這裡就知道這個題目的核心難度也就在於-- 如何儲存當前資料棧的最小值

這裡注意到,題設所要求設計的是棧結構,意味著資料只有單向進出的方式, 這是一個很關鍵的前提。

image.png

接下來按照題設的例子步驟,一步步來看(認真看 不然嗖的一下就過去了!):

  1. 初始時,資料棧為空,首先-2入棧,此時:

    資料棧[-2]  // 此時 棧內最小元素值為-2
  2. 接著,0入棧時,此時:

    資料棧[-2, 0] // 0 大於已有的最小值-2,那麼最小值還是-2,

    這裡有個關鍵點,當前狀態下,元素出棧的方式,只能是先出0,再出-2,也就是說,在-2出棧之前, 棧內元素的最小值始終是-2。  聽到這,腦海裡有沒有突然?!!!。
    image.png

  3. 彆著急,繼續入棧-3,此時:

    棧內元素為【-2,0,-3】// 最小值應當更新為-3,

    同理,當-3沒出棧時,棧內最小值都為-3; 當-3出棧以後,棧內的最小值應當為先前的一個最小值-2;

那麼 解法也就浮出水面了!!!

image.png

我們只需要另外維護一個單調遞減的棧,始終只存入比當前棧內最小值更小的元素即可!

(我知道還有部分同學看到這裡還是沒理解,沒關係)那麼我們依然舉個例子:

// 初始狀態如下
資料棧  [-2];
最小值棧 [-2];

// -2入棧後
資料棧  [-2];
最小值棧 [-2];

// 0入棧後 由於0比-2大,因此最小值棧不儲存-2
資料棧  [-2, 0];
最小值棧 [-2];

// -3入棧後,-3比-2小,因此最小值棧儲存-3
資料棧  [-2, 0, -3];
最小值棧 [-2, -3];

// -3出棧時,比較出棧元素是否是【最小值棧】的棧頂元素,是的話一起出棧;
資料棧  [-2, 0];
最小值棧 [-2];

從這裡可以看到,最小值棧,一直維護的是一個單調遞減的陣列,並且棧頂元素(陣列末尾元素)始終表示當前資料棧的最小值。

完整程式碼

理解了前面的核心內容,其實程式碼就不難寫了,最後貼上完成程式碼:

var MinStack = function() {
    this.dataStack = [];
    this.minStack = [];
};

MinStack.prototype.push = function(x) {
    this.dataStack.push(x);
    const len =  this.minStack.length;
    if(len === 0 || x <= this.minStack[len-1]){
        this.minStack.push(x);
    }
};

MinStack.prototype.pop = function() {
   const last = this.dataStack.pop();
   const len =  this.minStack.length;
   if(last === this.minStack[len-1]){
       this.minStack.pop();
   }
};

MinStack.prototype.top = function() {
    const len = this.dataStack.length;
    return len > 0 ? this.dataStack[len - 1] : null;
};

MinStack.prototype.min = function() {
    const len =  this.minStack.length;
    return this.minStack[len-1];
};

簡簡單單一道題又搞定了!
image.png

相關文章