代码随想录算法训练营第十一天| 20.有效的括号、1047.删除字符串中的所有相邻重复项、 150.逆波兰表达式求值

20.有效的括号

题目链接:20.有效的括号

文档讲解:代码随想录/有效的括号

视频讲解:视频讲解-有效的括号

状态:已完成(2遍)

解题过程 

看到题目的第一想法

 这个字符串只包括这六个括号,那结合栈的思维,从左往右遍历,每次有左括号的时候往栈里存一个左括号,遇到右括号的时候把栈pop一个出来看看对不对应。最后全部遍历完了,栈里没剩下的了就没问题。

本来想用charCodeAt来分别,但这三种括号两两之间的asc码差的还不一样,那就直接用字符串本身吧。

手搓一版:

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
    const stack = [];
    for (let i = 0; i < s.length; i++) {
        let kh = s[i];
        switch (kh) {
            case "{":
                stack.push("}");
                break;
            case "[":
                stack.push("]");
                break;
            case "(":
                stack.push(")");
                break;
            default:
                if (s[i]!==stack.pop()) return false;//如果相等不用管,已经pop过了
        }
    }
    return stack.length==0;
};

运行提交都没问题。 

看完代码随想录之后的想法 

还得是昨天先有了栈思维的基础,看到这题再联想栈的话可以想出解题思路。栈可以很好的在碰到右括号的时候查看离它最近的左括号是什么。

不过文字讲解的代码还是有一版简化版本:

// 简化版本
var isValid = function(s) {
    const stack = [], 
        map = {
            "(":")",
            "{":"}",
            "[":"]"
        };
    for(const x of s) {
        if(x in map) {
            stack.push(x);
            continue;
        };
        if(map[stack.pop()] !== x) return false;
    }
    return !stack.length;
};

总结

看似很复杂的题目,在栈面前确实变得很容易,好东西。


 1047.删除字符串中的所有相邻重复项

题目链接:1047.删除字符串中的所有相邻重复项

文档讲解:代码随想录/删除字符串中的所有相邻重复项

视频讲解:视频讲解-删除字符串中的所有相邻重复项

状态:已完成(2遍)

解题过程  

看到题目的第一想法

同样还是用栈,拿到一个字母,如果和栈pop出来的字母不一样,那么把pop出来的字母和遍历到的字母一起push进栈;如果遍历到的字母和栈pop出来的字母一样,那不用对栈操作,将遍历的本体删去重复的两个字母。

手搓一版:

/**
 * @param {string} s
 * @return {string}
 */
var removeDuplicates = function(s) {
    const stack = [];
    let arrS = s.split('');
    let len = s.length;
    stack[0] = arrS[0];
    for(let i = 1;i<len;){
        if(stack.pop()!==arrS[i]){
            stack.push(...[arrS[i-1],arrS[i]]);//刚刚pop出去的再加进去
            i++;
        }else{
            arrS.splice(i-1,2);//s中删掉重复的字母
            len-=2;
            i--;
        }
    }
    return arrS.join('');
};

运行、提交也没问题。 

 看完代码随想录之后的想法 

错付了,说好的栈呢,怎么解法把它当数组看了。这样一整,不用pop出来再push进去,也不用考虑怎么表示栈里最后一个元素是什么了。。。

讲解代码如下:

var removeDuplicates = function(s) {
    const result = []
    for(const i of s){
        if(i === result[result.length-1]){
            result.pop()
        }else{
            result.push(i)
        }
    }
    return result.join('')
};

总结

像这道题和上道题这种消消乐的类型,首先考虑用栈。

 二刷的时候直接用了数组的方法哈哈,前端考虑什么堆和栈嘛,数组一步到位。


 150.逆波兰表达式求值

题目链接:150.逆波兰表达式求值

文档讲解:代码随想录/逆波兰表达式求值

视频讲解:视频讲解-逆波兰表达式求值

状态:已完成(2遍)

解题过程  

看到题目的第一想法

观察了好一阵子题目给出的三个示例,我总结出了,当遍历到是数字的时候,push进栈;当遍历到符号的时候,把栈顶的数字拿出来放到此符号之后再push进去,再将栈顶的三个元素做一下运算,得出来的结果存进栈顶。一直循环往复直到最后。

判断是不是符号和数字我只想到穷举。。待会看看题解怎么说。

手搓一版:

/**
 * @param {string[]} tokens
 * @return {number}
 */
var evalRPN = function(tokens) {
    var isNumber = function(input){
        return input !== '+' && input !== '-' && input !== '*' && input !== '/';
    };
    const stack = [];
    for(let i =0;i<tokens.length;i++){
        if(!isNumber(tokens[i])){//如果是符号
            const x = stack.pop();
            stack.push(...[tokens[i],x]);//符号和栈顶的数字交换位置再push进去
            let math = eval(stack[stack.length-3]+stack[stack.length-2]+stack[stack.length-1]);//栈顶的三个元素拿出来做运算再存进去
            stack.splice(stack.length-3,3,Math.floor(math).toString());
        }else{
            stack.push(tokens[i]);
        }
    }
    return Number(stack[0]);
};

遇到一个问题,debug之后发现是运算得出 -0.045,floor之后给他变-1了,但题目要变0,改用parseInt试试;提交还只有11/21通过率。debug了一下发现2 - -3这种减负数会出错。受不了了,再写一个函数。

/**
 * @param {string[]} tokens
 * @return {number}
 */
var evalRPN = function (tokens) {
    var isNumber = function (input) {
        return input !== '+' && input !== '-' && input !== '*' && input !== '/';
    };
    var cal = function (num1, operator, num2) {
        switch (operator) {
            case '+':
                return Number(num1) + Number(num2);
            case '-':
                return Number(num1) - Number(num2);
            case '*':
                return Number(num1) * Number(num2);
            case '/':
                return Number(num1) / Number(num2);
        }
    };
    const stack = [];
    for (let i = 0; i < tokens.length; i++) {
        if (!isNumber(tokens[i])) {//如果是符号
            const x = stack.pop();
            let math = cal(stack[stack.length - 1],tokens[i],x);//栈顶的两个数字拿出来,中间加入运算符,做运算再存进去
            stack.splice(stack.length - 1, 1, parseInt(math).toString());
        } else {
            stack.push(tokens[i]);
        }
    }
    return Number(stack[0]);
};

终于没问题了!!!!!!!!! 

 看完代码随想录之后的想法 

卧槽,又写啰嗦了。判断是不是数字写复杂了;for循环和做运算也可以写在一起。

文字讲解代码如下:

var evalRPN = function (tokens) {
    const stack = [];
    for (const token of tokens) {
        if (isNaN(Number(token))) { // 非数字
            const n2 = stack.pop(); // 出栈两个数字
            const n1 = stack.pop();
            switch (token) { // 判断运算符类型,算出新数入栈
                case "+":
                    stack.push(n1 + n2);
                    break;
                case "-":
                    stack.push(n1 - n2);
                    break;
                case "*":
                    stack.push(n1 * n2);
                    break;
                case "/":
                    stack.push(n1 / n2 | 0);
                    break;
            }
        } else { // 数字
            stack.push(Number(token));
        }
    }
    return stack[0]; // 因没有遇到运算符而待在栈中的结果
};

总结

看了示例半天,能悟出来解题思路很满足了,奈何前前后后debug了一个小时,累的ep。判断是不是数字也写复杂了,难顶。

二刷属实没想起来位运算,我用了Math.floor,但是在除以负数的时候会出错,所以要用Math.trunc来代替  | 0  这个位运算 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值