目录
225. 用队列实现栈 (简单)
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作。
考点在pop()方法:
底层数据结构是先进先出的队列,每次 pop 只能从队头取元素;但是栈是后进先出,pop 要从队尾取元素。
解决方法简单粗暴,把队列前面的都取出来再加入队尾,让之前的队尾元素排到队头,这样就可以取出了。
/**
* @return {number}
*/
MyStack.prototype.pop = function() {
let len = this.queue.length
while(len > 1){
this.queue.push(this.queue.shift());
len--
}
return this.queue.shift()
};
232. 用栈实现队列 (简单)
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作
老题目了,考点还是在pop()方法
/**
* @return {number}
*/
MyQueue.prototype.pop = function() {
if(this.stack2.length) return this.stack2.pop()
while(this.stack1.length) {
this.stack2.push(this.stack1.pop())
}
return this.stack2.pop()
};
/**
* @return {number}
*/
MyQueue.prototype.peek = function() {
const x = this.pop()
this.stack2.push(x)
return x
};
如何解决括号相关的问题
20. 有效的括号 (简单)
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
不需看题解,注意情况:右括号多于左括号,左括号有剩余
var isValid = function(s) {
let stack = [], left = '([{'
for(c of s) {
if(left.includes(c)) {
stack.push(c)
} else {
let x = stack.pop()
if((x=='(' && c==')') || (x=='[' && c==']') || (x=='{' && c=='}')) continue
return false
}
}
if(stack.length) return false
return true
};
921. 使括号有效的最少添加 (中等)
给定一个由 ‘(’ 和 ‘)’ 括号组成的字符串 S,我们需要添加最少的括号( ‘(’ 或是 ‘)’,可以在任何位置),以使得到的括号字符串有效。
不需看题解
给一个栈,如果为),看栈顶有没有跟他抵消,没有则也压入栈。
最后看栈剩下多少个元素。
var minAddToMakeValid = function(s) {
let deque = []
for (c of s) {
if(c == '('){
deque.push(c)
} else {
if(deque[deque.length-1] == '('){
deque.pop()
} else{ //包括了栈为空
deque.push(c)
}
}
}
return deque.length
};
1541. 平衡括号字符串的最少插入次数(中等) fail
注意案例:
“))())(” 最左边两个),但只需要一个(就可以抵消
“( ()) ) ( ()) ) () ()) ))” 说明不能【(,2】这种方式存储,遇到)为【(,1】
而且使用抵消的方法,中途上述字符串变成"( ) ( ) () ))" ,自然右边的倒数第2个)会和倒数第3个使用来抵消前一个(。实际是不可以跳过去的
最终搞不定:看答案
var minInsertions = function(s) {
// need 记录需右括号的需求量
let res = 0, need = 0;
for (c of s) {
if (c == '(') {
// 一个左括号对应两个右括号
need += 2;
if (need % 2 == 1) {
// 插入一个右括号 : ()( need=3
res++;
// 对右括号的需求减一
need--;
}
}
if (c == ')') {
need--;
// 说明右括号太多了
if (need == -1) {
// 需要插入一个左括号
res++;
// 同时,对右括号的需求变为 1
need = 1;
}
}
}
return res + need
};
如果坚持使用栈,我做不出来的一个原因:栈同时保留了左括号和右括号,当抵消之后,不同距离的右括号是否能起作用是一个问题。
解决办法:只存储左括号,遇到右括号立即处理
个人感觉使用栈会记得更深刻
var minInsertions = function(s) {
let stack = [], res = 0
for(let i=0; i<s.length; i++) {
if(s[i] == '(') {
stack.push(s[i])
} else {
// 下一个为右括号
if(s[i+1]==')') {
if(stack.length) { //存在左括号则抵消
stack.pop()
} else { // 自加一个左括号
res++
}
i++ // 跳过下一个
} else { // 下一个为空 或 左括号 与自己无关
if(stack.length) { //存在左括号则抵消
res++ // 自加一个右括号
stack.pop()
} else { // 单独的右括号 需要两边加括号
res += 2
}
}
}
}
return res + stack.length * 2
};
32. 最长有效括号 (困难)
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度
官方题解
这题也是解决办法:只存储左括号,遇到右括号立即处理。只不过初始化时,只存一次右括号当作没效位置。
var longestValidParentheses = function(s) {
let stack = [-1] //有效位置的前一个为-1
let max = 0
for(let i=0; i<s.length; i++) {
if(s[i] == '(') {
stack.push(i) // 只存左括号
} else {
stack.pop() // 当前为右括号,栈需提供一个左括号
if(stack.length==0) { // 没有左括号匹配, i之前的子串都没效
stack.push(i) // 更新没效位置
} else { // 抵消一个左括号, 此时栈顶元素为没匹配位置
max = Math.max(max, i - stack[stack.length-1])
}
}
}
return max
};
代码随想录的栈与队列
1047. 删除字符串中的所有相邻重复项
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
就是处理入栈
var removeDuplicates = function(s) {
let stack = [s[0]]
for(let i=1; i<s.length; i++){
let top = stack[stack.length-1]
if(top == s[i]) {
stack.pop()
continue
}
stack.push(s[i])
}
return stack.join("")
};
150. 逆波兰表达式求值 (中等)
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
其实就是后缀表达式,笔试题常见
取整是用Math.trunc, 使用eval()预防3–2 这种表达式
var evalRPN = function(tokens) {
let stack1 = [];
let op = '+-*/';
for(val of tokens) {
if(!op.includes(val)) {
stack1.push(val)
} else {
let b = stack1.pop()
let a = stack1.pop()
let res = Math.trunc(eval(a + val + '(' + b + ')'))
stack1.push(res)
}
}
return stack1[0]
};
文章的优雅写法:
var evalRPN = function(tokens) {
const s = new Map([
["+", (a, b) => a - 0 + (b - 0)],
["-", (a, b) => b - a],
["*", (a, b) => b * a],
["/", (a, b) => parseInt(b / a)]
]);
const stack = [];
for (const i of tokens) {
if(!s.has(i)) {
stack.push(i);
continue;
}
stack.push(s.get(i)(stack.pop(),stack.pop()))
}
return stack[0];
};