JS:队列/栈——最长有效括号,平衡括号,后缀表达式

在这里插入图片描述

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];
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值