day11:栈与队列-20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值
LeetCode 20. 有效的括号
题目链接:
文章讲解:
https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html
视频讲解:
https://www.bilibili.com/video/BV1AF411w78g
思路和解法:
栈
按照题目描述,只有三种不匹配的情况
1、左括号多余,如([{}]()
,最左边的(
是多余的
2、左右括号类型不匹配,如[{(}}]
中间的(}
不匹配
3、右括号多余,如[{}]())))
,右边多了(
所以用栈模拟下这三种情况就是:
先说三种情况的共性:在遍历字符串时,遇到左括号时,将其对应的右括号放入到栈中,之所以将对应的右括号放入到栈中,是因为之后遍历到右括号时,方便直接与栈顶元素进行匹配,如果符合则可以直接从栈中弹出。
第一种情况:
遍历结束后,如果栈内还有元素,则说明左括号有多的,不符合题目要求
第二种情况:
第一次遍历到右括号时,与栈顶元素不匹配,说明中间有不对应的括号,不符合题目要求
第三种情况:
当还没有遍历完,但是栈已经为空了,说明右括号有多的,不符合题目要求
public class Solution {
public bool IsValid(string s) {
//字符串长度为单数的话,肯定不匹配
if(s.Length % 2 != 0)
return false;
Stack<char> stk = new Stack<char>();
//遍历字符串
for(int i = 0; i < s.Length; i++)
{
//当字符串为左括号时,对应的右括号入栈
if(s[i] == '(')
stk.Push(')');
else if(s[i] == '[')
stk.Push(']');
else if(s[i] == '{')
stk.Push('}');
//当遍历到的元素(右括号)与栈顶元素(左括号对应的右括号)不匹配时以及右括号多了的情况
else if(stk.Count == 0 || stk.Pop() != s[i])
return false;
}
//遍历结束后,如果相匹配的话,栈里面应该没有元素
return stk.Count > 0 ? false : true;
}
}
LeetCode 1047. 删除字符串中的所有相邻重复项
题目链接:
文章讲解:
https://programmercarl.com/1047.%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.html
视频讲解:
https://www.bilibili.com/video/BV12a411P7mw/
思路和解法:
栈
在删除相邻重复项的时候,其实就是要知道当前遍历的这个元素,我们在前一位是不是遍历过一样数值的元素,利用栈来存放,即遍历当前的这个元素的时候,去栈里看一下之前是不是遍历过相同数值的相邻元素。
public class Solution {
public string RemoveDuplicates(string s) {
Stack<char> stk = new Stack<char>();
foreach(char c in s)
{
if(stk.Count > 0 && stk.Peek() == c)
stk.Pop();
else
stk.Push(c);
}
//构建字符串
char[] resultArray = stk.ToArray();
Array.Reverse(resultArray);
string result = new string(resultArray);
return result;
}
}
StringBuilder
public class Solution {
public string RemoveDuplicates(string s) {
//拿字符串直接作为栈,省去了栈还要转为字符串的操作
StringBuilder res = new StringBuilder();
foreach(char c in s){
if(res.Length > 0 && res[res.Length-1] == c){
res.Remove(res.Length-1, 1);
}else{
res.Append(c);
}
}
return res.ToString();
}
}
LeetCode 150. 逆波兰表达式求值
题目链接:
文章讲解:
https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html
视频讲解:
https://www.bilibili.com/video/BV1kd4y1o7on/
思路和解法:
逆波兰表达式:一种后缀表达式,是一种很方便计算机来做运算的一种表达式。
简单地说,逆波兰表达式相当于是二叉树中的后序遍历,可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。
详情查看上面的文章讲解。
栈
模拟过程:
1、遍历这个字符串,遇到数字时则入栈。
2、遍历到操作符时,则取出栈顶的两个数字进行计算
3、计算完毕后,再将数据入栈,继续遍历字符串
public class Solution {
public int EvalRPN(string[] tokens) {
int num;
Stack<int> stk = new Stack<int>();
foreach(string s in tokens)
{
if(int.TryParse(s, out num))
{
stk.Push(num);
}
else
{
int num1 = stk.Pop();
int num2 = stk.Pop();
switch(s)
{
case "+":
stk.Push(num1 + num2);
break;
case "-":
stk.Push(num2 - num1);
break;
case "*":
stk.Push(num1 * num2);
break;
case "/":
stk.Push(num2 / num1);
break;
}
}
}
return stk.Pop();
}
}