食堂店小二兒教你學會棧

這是前端食堂的第41篇原創  


「觀感度:🌟🌟🌟🌟🌟」
前端

「口味:酸辣檸檬蝦」git

「烹飪時間:10min」github

理解棧 Stack

前端食堂裏的店小二兒對棧的理解很深入,咱們來聽聽他是怎樣理解棧的。web

店小二兒十分勤奮,前臺後廚的活兒他都幹,天天都要跑前跑後端顧客吃完的盤子。棧就像疊在一塊兒的盤子,客人美滋滋的吃完飯,店小二去收拾桌子撿起盤子時,都是從下往上一個一個的放盤子。而他在後廚櫥櫃上取盤子給廚師時,是從上往下一個一個依次的取。算法

這也就是所謂的 LIFO (Last In, First Out, 後進先出)。後端

在 JavaScript 中,咱們能夠經過數組來簡單模擬下棧:數組

function Stack() {
  var items = [];
  // 添加元素到棧頂
  this.push = function(element{
    items.push(element);
  }
  // 移除棧頂的元素,同時返回它們
  this.pop = function() {
    return items.pop();
  }
  // 返回棧頂的元素,不對棧作任何修改
  this.peek = function() {
    return items[items.length - 1];
  }
  // 判斷棧是否爲空,爲空則返回true,不然返回false
  this.isEmpty = function() {
    return items.length === 0;
  }
  // 返回棧裏的元素個數
  this.size = function() {
    return items.length;
  }
  // 清空棧
  this.clear = function() {
    items = [];
  }
}

棧的特色

  • 棧是一種「操做受限」的線性表,只能從一端插入或刪除數據。
  • 入棧和出棧的時間複雜度、空間複雜度都是 O(1)。

棧的應用

棧的應用有不少,好比咱們熟知的函數調用棧、瀏覽器的前進後退還有漢諾塔小遊戲等。瀏覽器

LeetCode 真題


84. 柱狀圖中最大的矩形
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

這是一道難度爲困難的題,不過你們不要被它所迷惑,其實它不是很難。微信

解決這道題,最直觀的辦法就是暴力求解。咱們能夠先來分析一波:前端工程師

讀題的第一遍,實際上就是要求在寬度爲 1 的 n 個柱子能勾勒出來的矩形的最大面積。

這不就是個幼兒園的數學問題嗎?

面積 = 底 * 高

擼它!

暴力法

方法一:雙重循環遍歷出全部的可能性,在遍歷的過程當中咱們還能夠求出最小的高度。

const largestRectangleArea = function(heights{
  let maxArea = 0;
  let len = heights.length;
  for (let i = 0; i < len; i++) {
    let minHeight = heights[i];
    for (let j = i; j < len; j++) {
      minHeight = Math.min(minHeight, heights[j]);
      maxArea = Math.max(maxArea, minHeight * (j - i + 1));
    }
  }
}

方法二:肯定一根柱子後,分別向先後兩個方向遍歷。

const largestRectangleArea = function(heights{
  let maxArea = 0;
  let len = heights.length;
  for (let i = 0; i < len; i++) {
    let left = i;
    let right = i;
    while (left >= 0 && heights[left] >= heights[i]) {
      left--;
    }
    while (right < len && heights[right] >= heights[i]) {
      right++;
    }
    maxArea = Math.max(maxArea, (right - left - 1) * heights[i]);
  }
  return maxArea;
}

可是這兩種方法的時間複雜度都是 O(n^2),空間複雜度是 O(1)。時間複雜度過高了,咱們須要想辦法進行優化。

使用單調遞增棧

咱們來思考一個問題,咱們究竟想要求的最大面積是什麼?

不妨拿起筆畫畫圖,我這裏幫你畫好了,觀察上圖,即可以得出:

其實就是以 i 爲中心,分別向左、向右找到第一個小於 heighs[i] 的兩個邊界,也就是以當前這根 i 柱子所能勾勒出的最大面積。

那麼,咱們爲何要藉助單調遞增棧這種數據結構呢?

單調遞增,也就是咱們能夠經過 O(1) 的時間複雜度肯定柱體 i 的左邊界!

又是以空間換時間的套路!

如何肯定右邊界?

只需遍歷一次柱體數組,將大於等於當前柱體的柱子們推入棧中,而當遍歷到的柱子高度小於棧頂的柱子高度時,這時咱們找到了右邊界,能夠將棧頂的柱子彈出棧 來計算矩形面積了!

處理特殊邊界狀況?

引入先後邊界,在柱體數組先後各放入一根高度爲 0 的柱子。這樣便無需考慮棧空以及棧中還有剩餘柱子的狀況啦!

ok,上代碼!

const largestRectangleArea = function(heights{
  let maxArea = 0;
  let stack = [];
  heights.push(0);
  heights.unshift(0);
  // heights = [0, ...heights, 0]; 你也能夠這樣寫
  for (let i = 0; i < heights.length; i++) {
    while (stack.length > 0 && heights[stack[stack.length - 1]] > heights[i]) {
      maxArea = Math.max(maxArea, heights[stack.pop()] * (i - stack[stack.length - 1] - 1));
    }
    stack.push(i);
  }
  return maxArea;
}
  • 時間複雜度:O(N)
  • 空間複雜度:O(N)

但願本文可讓你對棧的理解更深一層,若是你還沒看過癮,能夠移步上方專輯中看個人其餘算法系列文章。


❤️愛心三連擊

1.若是你以爲食堂酒菜還合胃口,就點個在看支持下吧,你的「在看」是我最大的動力。

2.關注公衆號前端食堂,「吃好每一頓飯!」

3.本文已收錄在前端食堂 Github github.com/Geekhyt,但願能獲得你的小星星鼓勵。


公衆號:前端食堂


掘金:童歐巴


知乎:童歐巴


這是一個終身學習的男人,他在堅持本身熱愛的事情,歡迎加入前端食堂,和這個男人一塊兒開心的變胖~

推薦閱讀:

九月福利第二彈!送JavaScript 經典「紅寶書」

前端工程師如何自學後端知識體系?

   在看和轉發是莫大鼓勵❤️


本文分享自微信公衆號 - 前端食堂(webcanteen)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索