定义
栈是一种特殊的线性表,它只能在一个表的一个固定端进行数据结点的插入和删除操作。栈按照后进先出的原则来存储数据,也就是说,先插入的数据将被压入栈底,最后插入的数据在栈顶,读出数据时,从栈顶开始逐个读出。栈在汇编语言程序中,经常用于重要数据的现场保护。栈中没有数据时,称为空栈。
模拟实现
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 falsereturn 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) // 初始化结果数组,注意数组定长,占位为0for(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)
参考链接 https://github.com/lznbuild/my-blog/issues/26 https://mp.weixin.qq.com/s/3kDSOHyd-qOw7apzj0Z9YQ
