栈的模拟实现及常见算法
定义
栈是一种特殊的线性表,它只能在一个表的一个固定端进行数据结点的插入和删除操作。栈按照后进先出的原则来存储数据,也就是说,先插入的数据将被压入栈底,最后插入的数据在栈顶,读出数据时,从栈顶开始逐个读出。栈在汇编语言程序中,经常用于重要数据的现场保护。栈中没有数据时,称为空栈。
模拟实现
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)
参考链接
语雀链接🔗 https://www.yuque.com/suihangadam
归来卧占楼千尺,梦落沧波明月舟。