力扣-20-有效的括号
这题看到的第一眼想法就是“栈”,因为只有最内层括号匹配了,才能匹配外层的括号
思路
要有正确的顺序,那么这样“({})”应该是非法的,“{{}}”这样应该也是非法,“(((())))”这样是否非法?不非法?
需要考虑的有两点
- 是否匹配
- 嵌套顺序
给的是一个字符串
- 从左到右依次扫描每一个字符,扫描到左括号(1.栈空,直接入栈;2.栈不空,判断栈顶元素优先级是否大于当前元素,大于返回非法,小于入栈)
- 扫描到右括号,判断与栈顶元素是否匹配,匹配则栈顶元素出栈,不匹配返回非法
有两个难点:“怎么判断优先级”以及“怎么判断匹配”,感觉要写一堆if-else了
坑
这是一道简单题,但通过率只有40%几
- “{{{}}}”是合法的,“[{}]”也是合法的
- 如果不先判空就直接stack.top会报错
两次NG,第一次“(])”,第二次“]”
不优雅的第一版ACCEPT代码
class Solution {
public:
bool isValid(string s) {
stack<char> st;
int len = s.size();
for (int i = 0; i < len; ++i) {
// 遇到左括号,判断压栈
if (s[i] == '{' || s[i] == '[' || s[i] == '(') {
st.push(s[i]);
}
// 遇到右括号,弹栈
else if (s[i] == ')') {
if (st.size() > 0) {
if (st.top() == '(') {
st.pop();
}
else {
return false;
}
}
else {
return false;
}
}
else if (s[i] == ']') {
if (st.size() > 0) {
if (st.top() == '[') {
st.pop();
}
else {
return false;
}
}
else {
return false;
}
}
else if (s[i] == '}') {
if (st.size() > 0) {
if (st.top() == '{') {
st.pop();
}
else {
return false;
}
}
else {
return false;
}
}
}
// 如果栈里面还剩左括号呢
if (st.size() != 0) {
return false;
}
return true;
}
};
内存消耗大了
题解
官方题解给出的也是用栈
基本思路跟我是一样的,但是给出了一些优化,比如:字符串长度为奇数时就直接返回false
了,因为不可能配对
然后题解中用到了unordered_map,这个其实我也想过,看能不能替代栈
敲一遍,理解一下吧
相比之下的优点有:
- 通过判断字符长度减少了很多判断步骤
- 用unordered_map实现配对,避免了每次敲括号字符的繁琐和易出错,同时利用到了其提供的方法检查、匹配括号
- 最后判空我还要写个判断真是脑子抽了
- 为什么我想到的是
size
方法==0,而不是isEmpty
方法?
class Solution {
public:
bool isValid(string s) {
int n = s.size();
// 排除长度为奇数的情况,一定不配对
if(n%2==1){
return false;
}
// 用来配对括号
unorder_map<char,char> pairs = {
{')','('},
{']','['},
{'}','{'}
}
stack<char> stk;
for(char:s){
// 用来检查是否存在给定键的函数
// 这也是为什么要把右括号作为键值了
if(pairs.count(ch)){
if(stk.empty()||stk.top()!=pairs[ch]){
return false;
}
}
stk.pop();
}else{
stk.push(ch);
}
// 不用像我一样单独写一个判断
return stk.empty();
}
};
为什么好像…内存使用没什么优化的样子
后记
其实评论区还有其他的思路方法,比如ASCII码(是不是只有C++能这么用)、字符替换啥的,兴许这个思路就不是最优最巧妙的吧