Day10:代码随想录算法训练营第十天| 栈与队列基础 力扣20.有效的括号、力扣1047. 删除字符串中的所有相邻重复项、力扣150. 逆波兰表达式求值
力扣20.有效的括号
题目描述:
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例 2:
输入: "()[]{}"
输出: true
示例 3:
输入: "(]"
输出: false
示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true
思路:
结合括号的顺序,因为后来的括号会先得到匹配,这里要用栈而不是队列。
显然左括号一定是先出现的,故每次出现左括号时,我们把相应的右括号压入栈,这就实现了一次匹配。然后遍历到右括号时,如果有相等的就弹出栈。
这里一共有三种情况:
- 第一种是左侧的括号多了,表现在遍历完了字符串,栈中却仍然有剩余元素。
- 第二种是在匹配过程中,出现了对应括号不匹配。
- 第三种是右侧括号多了,表现在遍历字符串过程中,栈提前为空了。
代码如下:
class Solution{public:bool isValid(string s) {//剪枝操作,如果字符串本身的长度不是2的倍数,那显然是要么多了,要么少了。if(s.size() % 2 != 0){return false;}stack<char> stIn;/*这里要注意的是在处理第二和第三种情况时,要先处理第三种情况,即把stIn.empty()写在前面。这是因为||运算符是有一个满足就可以执行后面的代码,也就是说第一个满足了就不会判断第二个了。如果把这句放在后面时,且恰好此时栈是空的,程序会先判断栈顶元素与s[i]是否相等,而此时根本没有栈顶元素,程序就会报错数组越界。*/for(int i = 0; i < s.size(); i++){if(s[i] == '(')stIn.push(')');else if(s[i] == '[')stIn.push(']');else if(s[i] == '{')stIn.push('}');else if(stIn.empty() || stIn.top() != s[i])return false;else stIn.push(s[i]);}return stIn.empty();
}
};
力扣1047.删除字符串中的所有相邻重复项
题目描述:
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca"
输出:"ca"
解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
提示:
1 <= S.length <= 20000
S 仅由小写英文字母组成。
思路:
这是一个多步的删除,既要对每次删除后的结果再次检验,用栈是比较好的。
还是一个循环遍历字符串,如果栈顶元素与当前s[i]相等了,那就是相邻了,直接把这个元素出栈就行了,否则就把s[i]压入栈。然后一直这样操作,最后再把栈里的元素保存到数组里,这里注意要把数组逆序后输出,因为栈把顺序给弄反过来了。
代码如下:
class Solution {
public:string removeDuplicates(string s) {stack<char> stIn;string result;//每个元素遍历时,在放入栈之前都与前一个比较是否相同,相同则为相邻的两个字符。for(int i = 0; i < s.size(); i++){if(!stIn.empty() && stIn.top() == s[i]){stIn.pop();}else{stIn.push(s[i]);}}//这边把栈里的字符全部放进一个新的字符串中while(!stIn.empty()){result += stIn.top();stIn.pop();}//由于栈是先进后出,则需要把字符串翻转已符合答案顺序reverse(result.begin(), result.end());return result;}
};
** ## 力扣.150 逆波兰表 **
题目描述:
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: ["2", "1", "+", "3", " * "]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入: ["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
以下为力扣对逆波兰表达式的解释:
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
思路:
这道题它明说了适合用栈,至于为什么,其实这道题有点像力扣1047,都是相邻的,一个是删去,一个是做运算。大致就是一个一个压入栈,检测到了运算符,就立刻获得此时的栈顶元素和其的下一个元素,然后对它们做相应运算符的运算,然后把结果再压入栈。
代码如下:
class Solution {
public:int calculation(stack<long long> &st, string ch){long long a = st.top();st.pop();long long b = st.top();st.pop();if(ch == "+"){return a + b;}else if(ch == "-"){return b - a;//这里注意是b - a,因为入栈时有逆序,所以要反过来}else if(ch == "/"){return b / a;//同上}else{return a * b;}}int evalRPN(vector<string>& tokens) {stack<long long> stIn;for(int i = 0; i < tokens.size(); i++){//每当检测到算数符,就把相邻的数做运算压入栈中if(tokens[i] == "+"){stIn.push(calculation(stIn, "+"));}else if(tokens[i] == "-"){stIn.push(calculation(stIn, "-"));}else if(tokens[i] == "/"){stIn.push(calculation(stIn, "/"));}else if(tokens[i] == "*"){stIn.push(calculation(stIn, "*"));}else{stIn.push(stoll(tokens[i]));//stoll是把字符串转变为long long型}}return stIn.top();//最后剩下的就是最后的结果}
};
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
