定義
棧是一種特殊的線性表,它只能在一個表的一個固定端進行資料結點的插入和刪除操作。棧按照後進先出的原則來儲存資料,也就是說,先插入的資料將被壓入棧底,最後插入的資料在棧頂,讀出資料時,從棧頂開始逐個讀出。棧在組合語言程式中,經常用於重要資料的現場保護。棧中沒有資料時,稱為空棧。
模擬實現
class Stack{ constructor(){ this.stack = []; this.top = 0; this.max=10000; }; // 入棧 push(item){ if(this.top<this.max){ this.top++; this.stack.push(item); }else{ consle.error('棧溢位') } } // 出棧 pop(){ if(this.top > 0) { let x = this.stack.pop(); this.top--; return x; }else{ console.log('棧已經為空') } } // 判斷棧是否為空 empty(){ return this.top === 0; } // 返回位於棧頂的元素 peek(){ return this.stack[this.top]; } // 棧的大小 size(){ return this.top; } }
常見應用
進位制轉換
利用棧將轉化數字的進位制,假設將數字n轉換為以b為基數的數字,方法如下:
- 最高位為n % b,將此位壓入棧
- 使用Math.floor(n/b)代替n
- 重複步驟1和2,直到n等於0,且沒有餘數
- 持續將棧內元素彈出,直到棧為空
function mulBase(num, base){ var stack = new Stack(); do { stack.push(num % base); num = Math.floor(num /= base) } while(num > 0) var str = ''; while(stack.length() > 0){ str += stack.pop(); } return str }
迴文判斷
利用棧,可以輕鬆判斷一個字串是否是迴文(迴文指一個字串從前往後寫和從後往前寫都一樣)
function isPalindrome(word){ var stack = new Stack(); for(var i = 0, len = word.length; i++){ stack.push(word[i]); } var rword = ''; while(stack.length() > 0){ rword += stack.pop(); } return rword == word; }
當然正常我們直接使用
var arr = Array.prototype.slice.call(word); return arr.reverse().join('') == word
實現特殊棧
實現一個特殊的棧,有棧的正常方法,能返回棧裡的最小值。要求時間複雜度為O(1)
思路:建立兩個棧,一個棧 data 放正常的資料。另一個棧 mins 放當前資料中的最小值。例如:若新新增的資料小於當前的最小值,兩個棧都新增新的資料。若新新增的資料大於當前棧中的最小值,mins 仍然新增當前最小值。
而且,data出資料的時候,mins同時出棧。
常見的演算法
有效的括號
leetCode 20:給定一個只包括 '(',')','{','}','[',']' 的字串,判斷字串是否有效。
有效字串需滿足:左括號必須用相同型別的右括號閉合。左括號必須以正確的順序閉合。
var isValid = function(s) { let map = { '(': -1, ')': 1, '[': -2, ']': 2, '{': -3, '}': 3 } let stack = [] for (let i = 0; i < s.length; i++) { if (map[s[i]] < 0) { stack.push(s[i]) } else { let last = stack.pop() if (map[last] + map[s[i]] != 0) return false } } if (stack.length > 0) return false return true }
每日溫度
LeetCode 739: 根據每日氣溫列表,請重新生成一個列表,對應位置的輸出是需要再等待多久溫度才會升高超過該日的天數。如果之後都不會升高,請在該位置用 0 來代替。
例如,給定一個列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的輸出應該是 [1, 1, 4, 2, 1, 1, 0, 0]。
const dailyTemperatures = function(T) { const len = T.length // 快取陣列的長度 const stack = [] // 初始化一個棧 const res = (new Array(len)).fill(0) // 初始化結果陣列,注意陣列定長,佔位為0 for(let i=0;i<len;i++) { // 若棧不為0,且存在打破遞減趨勢的溫度值 while(stack.length && T[i] > T[stack[stack.length-1]]) { // 將棧頂溫度值對應的索引出棧 const top = stack.pop() // 計算 當前棧頂溫度值與第一個高於它的溫度值 的索引差值 res[top] = i - top } // 注意棧裡存的不是溫度值,而是索引值,這是為了後面方便計算 stack.push(i) } // 返回結果陣列 return res };
圖解連結:
其他
利用堆疊,還可以解決如下常見問題:
- 求解算術表示式的結果(LeetCode 224、227、772、770)
- 求解直方圖裡最大的矩形區域(LeetCode 84)
參考連結