「觀感度:🌟🌟🌟🌟🌟」
前端
「口味:酸辣檸檬蝦」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 真題
這是一道難度爲困難的題,不過你們不要被它所迷惑,其實它不是很難。微信
解決這道題,最直觀的辦法就是暴力求解。咱們能夠先來分析一波:前端工程師
讀題的第一遍,實際上就是要求在寬度爲 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,但願能獲得你的小星星鼓勵。
公衆號:前端食堂
掘金:童歐巴
知乎:童歐巴
這是一個終身學習的男人,他在堅持本身熱愛的事情,歡迎加入前端食堂,和這個男人一塊兒開心的變胖~
推薦閱讀:
在看和轉發是莫大鼓勵❤️
本文分享自微信公衆號 - 前端食堂(webcanteen)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。