这一期仍然是栈的使用技巧,通过这期的训练我们可以更好的了解到在应对什么题目时可以考虑用栈这个数据结构来实现,更加方便。让我们首先来看看第一题
20. 有效的括号 - 力扣(LeetCode)https://leetcode.cn/problems/valid-parentheses/这道题相信在学校里学过数据结构的同学应该并不陌生,这道题是一道在学习栈的时候的一道十分经典的题型,起初第一次接触的时候,多少会有点感觉难,现在做来还算很容易的。
题目要求就是将所有的括号匹配起来,主要有两种情况会匹配失败,一种是左括号或者右括号出现多余的情况,另一种情况是前一个括号与后一个括号不能连续匹配,我们可以根据栈这个数据结构的特点,使左括号字符都放进去,遇到右括号的时候,top一下看看栈顶元素是否为相匹配的左括号,如果相匹配我们将其弹出栈,然后接着遍历,如果不匹配我们直接return false,值得注意的是:如果在碰到右括号时候栈为空则说明栈中没有左括号,那么此时直接弹出,说明右括号有多余的。如果将整个字符都遍历完了,依然没有return,那么则说明第二种情况已经判断完毕,并没有括号不匹配的情况出现,但是此时并不代表就一定没有错误,当匹配完毕之后如果栈中还剩下括号说明左括号有多余的。
class Solution {
public:
bool isValid(string s) {
stack<char> arr1;
for(int i=0;i<s.size();i++){
if(s[i]!=')'&&s[i]!=']'&&s[i]!='}')
arr1.push(s[i]);
if(s[i]==')'){
if(arr1.empty()==true||arr1.top()!='(')return false;
else
arr1.pop();
}
if(s[i]==']'){
if(arr1.empty()==true||arr1.top()!='[')return false;
else
arr1.pop();
}
if(s[i]=='}'){
if(arr1.empty()==true||arr1.top()!='{')return false;
else
arr1.pop();
}
}
if(arr1.empty()==true)return true;
else return false;
}
};
还有另一种思路:在遇到左括号时候往栈里直接加入右括号,然后碰到右括号时候在进行判断,和上一种思路基本上是一样的。
1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/这道题是消除字符串中连续的字符,差不多和消消乐差不太多,只要有相邻重复就直接删除,所以并不是我们第一眼看到只有一处相邻相同字符就只删一次,可能在删除一处之后又有新的元素碰到一起,这时栈派上了用场,它可以存储我们遍历过的数据,我们只需要判断当前遍历的数据是否和栈顶元素一样,一致就将其弹出,这样不仅解决了表面的相邻相同字符消去,当消去后如果有两个新的相邻相同元素碰到一起了,我们也能发现并消除他们,一举多得。
class Solution {
public:
string removeDuplicates(string s) {
string result;
for(int i:s){
if(result.empty()||i!=result.back())
result.push_back(i);
else
result.pop_back();
}
return result;
}
};
上面的代码我们用字符串来模拟栈的一个实现,让字符串的头部充当栈底,尾部充当栈顶,这样做的好处是避免了直接使用栈的时候数据元素是倒序且还要转换为字符串输出。
150. 逆波兰表达式求值 - 力扣(LeetCode)https://leetcode.cn/problems/evaluate-reverse-polish-notation/逆波兰表达式求值,这道题的难度是中等题,并不是是它有多么难的思路,而是如果你没有接触到这个题,不是很容易想到解题思路,逆波兰表达式,实际上就是一种后缀表达式,可以把我们日常熟悉的一个等式(1+2)*(3*4)看成中序表达式,用纸画树形图很容易得出,那么后续表达式大题运算思路就是两个数遇到符号再进行运算操作,没遇到符号时候先保留起来,每次遇到符号拿出两个操作数操作,这种思路很适用于栈的数据结构。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int>result;
for(int i=0;i<tokens.size();i++){
if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/"){
long nums1=result.top();result.pop();long nums2=result.top();result.pop();
if(tokens[i]=="+")
result.push(nums2+nums1);
else if(tokens[i]=="-")
result.push(nums2-nums1);
else if(tokens[i]=="*")
result.push(nums2*nums1);
else
result.push(nums2/nums1);
}
else
result.push(stoll(tokens[i]));
}
return result.top();
}
};
具体代码如上,在未碰到操作符时,将数字入栈,遇到操作符再取出两个操作符,值得注意的是操作数顺序很重要是第二个操作数相对于第一个操作数来进行操作,数据放入里的stoll函数,作用是将字符串转换为long数据类型。此外这道题并不需要我们来判断传输进来的数据是否合法,只需要我们写出判断字符和数据的代码即可。
代码均可ac。