赞
踩
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
最小栈主要用来记录栈中最小元素,方便O(1)复杂度获取。
算法思想:定义两个栈,一个栈正常的弹出和推进,另一个栈的栈顶保持当前正常栈的最小值。
以力扣155—最小栈来讲解。
1、定义两个栈:
var MinStack = function() {
this.stack = []
this.minStack = [Infinity]
};
2、写push方法,stack正常推入元素,minStack每次推入都要和当前栈顶比较,若当前元素小于栈顶元素的话,则推入,否则继续推入当前栈顶元素。(原因:保持minStack的栈顶一直都是stack的最小值)
MinStack.prototype.push = function(val) {
this.stack.push(val)
this.minStack.push(Math.min(val,this.minStack[this.minStack.length - 1]))
};
3、写pop方法,两个栈都一起pop,因为如果只有stack pop的话,minStack就不能保持它的栈顶是stack的最小值了。
MinStack.prototype.pop = function() {
this.stack.pop()
this.minStack.pop()
};
4、取栈顶即stack中的栈顶元素。
MinStack.prototype.top = function() {
return this.stack[this.stack.length - 1]
};
5、取最小值即minStack的栈顶元素。
MinStack.prototype.getMin = function() {
return this.minStack[this.minStack.length - 1]
}
单调栈适用于对序列中每个元素,寻找离当前元素左边最近最小(大)的,右边最近最小(大)的。
算法思想:
核心代码:
// 核心代码(找下一个最大(栈底->栈顶:大 -> 小))
for(let i = 0; i < nums2.length; i++){
let num = nums2[i]
while(stack.length !== 0 && num > nums2[stack[stack.length - 1]]){
map.set(stack[stack.length - 1],i)
stack.pop()
// stack.push(i)
}
stack.push(i)
}
相关例题有:
1.力扣496—下一个更大元素I
解法1:暴力解法
var nextGreaterElement = function (nums1, nums2) { // 暴力解法 let n = nums1.length let m = nums2.length let res = new Array(n).fill(0) for (let i = 0; i < n; i++) { let j = 0; while (j < m && nums1[i] !== nums2[j]) { j++ } let k = j + 1 while (k < m && nums2[k] < nums2[j]) { k++ } res[i] = k < m ? nums2[k] : -1 } return res }
解法2:单调栈 + Map
var nextGreaterElement = function (nums1, nums2) { // 单调栈 let stack = [] let res = [] let map = new Map() for(let i = 0; i < nums2.length; i++){ let num = nums2[i] while(stack.length !== 0 && num > nums2[stack[stack.length - 1]]){ map.set(stack[stack.length - 1],i) stack.pop() // stack.push(i) } stack.push(i) } console.log(map) for(let i = 0; i < nums1.length; i++){ let key = nums2.indexOf(nums1[i]) console.log(key) if(!map.get(key)){ res.push(-1) }else{ res.push(nums2[map.get(key)]) } } return res }
2.力扣503—下一个更大元素II
解法类似,只是题目说的是循环数组,其实把该数组循环次数改为2*n-1次即可。(因为是自己找自己,寻找下标已经确定好了,所以就不需要map记录了)。
var nextGreaterElements = function(nums) { let stack = [] let map = new Map() let n = nums.length let res = new Array(n).fill(-1) for(let i = 0; i < 2 * n - 1; i++){ let num = nums[i % n] while(stack.length !== 0 && num > nums[stack[stack.length - 1]]){ res[stack[stack.length - 1]] = num stack.pop() } stack.push(i % n) } return res };
1.力扣20—有效的括号
解决思路:
1.定义一个空栈
2.遍历字符串,若当前元素为左括号,就将其入栈。否则取栈顶(注意:不是出栈),判断当前元素与栈顶元素是否是一对的,如果是一对的话,就将栈顶元素出栈,否则直接返回false。
3.最后检查栈是否为空,若为空,返回true,否则返回false。
var isValid = function(s) { let stack = [] for(let i = 0; i < s.length; i++){ let str = s[i] if(str === '(' || str === '{' || str === '['){ stack.push(str) }else{ let start = stack[stack.length - 1] if((start === "(" && str === ')') || (start === "{" && str == '}') || (start == '[' && str == ']')){ stack.pop() }else{ return false } } } return stack.length == 0 ? true : false };
2.力扣71—简化路径
思路:
1.对字符串根据“/”分割,得到一个拥有所有文件名的数组。
2.遍历分割后的数组,判断当前元素是否为空或为“.”,表示在当前目录下,直接continue,不用将其处理
3.若为“…”,表示在上一层目录中,将栈顶元素出栈
4.否则,将当前元素压入栈中
5.最后使用“/”将栈中的元素拼接起来,在最前面加个“/”,表示在当前目录下。
var simplifyPath = function (path) { let stack = [] let arr = path.split('/') for (let i = 0; i < arr.length; i++) { let val = arr[i] if (val == '' || val === '.') { continue } else if (val === '..') { stack.pop() } else { stack.push(val) } } return '/' + stack.join('/') };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。