代码随想录day10--栈的应用

LeetCode20.有效的括号

题目描述:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

解题思路:

*有很多同学在解题的时候,会在遍历左括号的时候,将左括号放入栈中,遇到右括号再取出,但是这样其实会麻烦很多;其实可以再匹配左括号的时候,将右括号入栈,就只需要比较当前元素和栈顶是否相等就可以了,会比左括号入栈简单很多。

·括号匹配是一个经典的使用栈解决的问题,题目的意思就是,有左括号,相应的也要有右括号

·仔细分析,会有三种不匹配的情况

1.字符串里左括号多余了eg:([{}]()

2.括号没有多余,但是类型不匹配,其实这个和第一个是差不多的,所以可以用同一个表达式解决,但是为了方便同学们理解这道题,所以单独列出。eg:([{}}}

3.字符串里右方向的括号多余了,如果栈空了但是依旧出现右括号说明不匹配eg:([{}])))

·这里还有一个隐藏的点,就是字符串一定得是偶数,如果字符串是奇数就一定不匹配

代码如下:

class Solution {
public:
    bool isValid(string s) {
        if(s.size() % 2 != 0) return false;//如果s的长度为奇数,直接不匹配
        stack st;
        for(int i = 0;i < s.size();i++){
            if(s[i] == '(') st.push(')');
            else if(s[i] == '[') st.push(']');
            else if(s[i] == '{') st.push('}');

            //出现栈空没有匹配元素,但是未遍历完成的情况说明不匹配
            //出现栈顶元素不匹配
            else if(st.empty() || st.top() != s[i]) return false;
            else st.pop();
        }
        return st.empty();//如果最终结果为空说明匹配,不为空则不匹配
    }
};

·时间复杂度:O(n)

·空间复杂度:O(n)

总结:

这道题的想法比较巧妙,代码实现难度并不大,技巧性的题目逻辑比较重要。

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

题目描述:

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

解题思路:

·这道题的思路其实和上一题解题思路是一样的,上一题是匹配左右括号,这题是匹配相邻元素,最后再做消除操作

·使用栈来存放,往栈中存放遍历过的元素,当遍历当前的这个元素的时候,去栈中看是否遍历过相同数值的相邻元素,同学们可以直接在纸上进行操作

·因为从栈中取出的元素是倒序的,最后需要再增加一步反转字符串

代码如下:

class Solution {
public:
    string removeDuplicates(string S) {
        stack st;
        for(char s:S){
            if(st.empty() || s != st.top()){
                st.push(s);
            }else{
                st.pop();//如果s和栈顶元素一致,则移除
            }
        }
        string result = "";
        while(!st.empty()){//将栈中元素放到result字符串中 
            result += st.top();
            st.pop();
        }
        reverse(result.begin(),result.end());因为从栈中取出是倒序,所有需要反转
        return result;
    }
};

·时间复杂度:O(n)

·空间复杂度:O(n)

番外

这道题也可以不使用栈解题,可以直接对字符串进行操作

代码如下:

class Solution {
public:
    string removeDuplicates(string S) {
        string result;
        for(char s:S){
            if(result.empty() || result.back() != s){ //不为空或最后一个字符于当前字符不相等
                result.push_back(s);//添加元素
            }else{
                result.pop_back();//移除元素
            }
        }
        return result;
    }
};

·时间复杂度:O(n)

·空间复杂度:O(1)

总结

这道题比上一题还简单一些,可以直接想到,没有那么多种情况,依旧是需要多次练习

LeetCode150.逆波兰表达式求值

题目描述:

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

解题思路:

·其实逆波兰表达式相当于二叉树中的后序遍历。可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树,但是没必要从二叉树的角度去解决,只需要知道逆波兰表达式是用后序遍历的方式把二叉树序列化了。

·本题中每一个子表达式要得出一个结果,再用这个结果进行运算,那么就是和上一题,相邻字符串消除的过程很像了吗(运算字符前两个数字进行相对应的运算,再存入栈中)

代码如下:

class Solution {
public:
    int evalRPN(vector& tokens) {
        stack st;
        for(int i = 0;i < tokens.size();i++){
            if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){
                long long num1 = st.top();
                st.pop();
                long long num2 = st.top();
                st.pop();
                if(tokens[i] == "+") st.push(num2 + num1);
                if(tokens[i] == "-") st.push(num2 - num1);
                if(tokens[i] == "*") st.push(num2 * num1);
                if(tokens[i] == "/") st.push(num2 / num1);
            }else{
                st.push(stoll(tokens[i]));
            }
        }
        int result = st.top();
        st.pop();
        return result;
    }
};

·时间复杂度:O(n)

·空间复杂度:O(n)

总结:今天的题目都是技巧题,代码理解难度都不高,但是都需要反复练习,并且要将其融会贯通,可以使用在别的情形中。

你可能感兴趣的:(java,开发语言)