力扣日记10.25-【栈与队列篇】有效的括号

力扣日记:【栈与队列篇】有效的括号

日期:2023.10.25
参考:代码随想录、力扣

20. 有效的括号

题目描述

难度:简单

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

有效字符串需满足:

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 ‘()[]{}’ 组成

题解

cpp ver
class Solution {
#define SOLUTION 2
public:
    bool isValid(string s) {
#if SOLUTION == 1
        // 对于([])这种情况,'[]'会先于'('出,即后进先出
        // ([)] 是无效字符
        if (s.size() == 0) {
            return true;
        }
        stack<char> st;
        st.push(s[0]);
        for (int i = 1; i < s.size(); i++) {
            if (!st.empty()) {
                if (st.top() == '(') {
                    if (s[i] == ']' || s[i] == '}') {
                        return false;
                    } else if (s[i] == ')') {
                        st.pop();
                    } else {
                        st.push(s[i]);
                    }
                } else if (st.top() == '[') {
                    if (s[i] == ')' || s[i] == '}') {
                        return false;
                    } else if (s[i] == ']') {
                        st.pop();
                    } else {
                        st.push(s[i]);
                    }
                } else if (st.top() == '{') {
                    if (s[i] == ')' || s[i] == ']') {
                        return false;
                    } else if (s[i] == '}') {
                        st.pop();
                    } else {
                        st.push(s[i]);
                    }
                }
            } else {
                if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
                    return false;
                } else {
                    st.push(s[i]);
                }
            } 
        }
        if (st.empty()) {
            return true;
        }
        return false;
#elif SOLUTION == 2 // 代码随想录版本
        // 遇到 左括号时,将对应右括号加入栈
        // 当遍历到 右括号时,再与栈顶的右括号匹配——如果相同则弹出(匹配成功);不同则非有效;栈空了也非有效
        // 遍历完栈非空,也为无效字符串
        
        // 如果s长度为奇数,一定不匹配
        if (s.size() % 2 != 0) return false;

        stack<char> 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() && s[i] != st.top()) { // s[i]不是左括号,说明是右括号,则开始匹配
                // 与栈顶元素不同,说明不匹配
                return false;
            } else if (st.empty()) { // 栈提前空了,说明右括号多余
                return false;
            } else { // 剩下情况即为st.top() 与 s[i]相等 //(!st.empty() && s[i] == st.top()) {
                st.pop(); // 匹配成功,弹出
            }
        }
        // 遍历完栈非空,也为无效字符串
        return st.empty();
#endif
    }
};
go ver
func isValid(s string) bool {
    // s 长度为奇数
    if len(s) % 2 != 0 {
        return false
    }

    st := make([]byte, 0) // byte 类似于 字符类型

    for i := 0; i < len(s); i++ {
        if s[i] == '(' {
            st = append(st, ')')
        } else if s[i] == '[' { 
            st = append(st, ']')
        } else if s[i] == '{' {
            st = append(st, '}')
        } else if len(st) > 0 && st[len(st) - 1] != s[i] {
            return false
        } else if len(st) == 0 {
            return false
        } else {
            st = st[:len(st) - 1]
        }
    }

    return len(st) == 0
}

复杂度

时间复杂度:O(n)
空间复杂度:O(n)

思路总结

  • 栈由于其结构的特殊性,非常适合做对称匹配类题目
  • 字符串里括号不匹配的几种情况
  • 第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
    第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
    第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
    ——By 代码随想录

  • 代码随想录的解法思路:
    • 遇到 左括号时,将对应右括号加入栈
    • 当遍历到 右括号时,再与栈顶的右括号匹配——如果相同则弹出(匹配成功);不同则非有效;栈空了也非有效
    • 遍历完栈非空,也为无效字符串
  • 我的解法则类似于穷举,且在遇到左括号时直接将左括号放进来,导致在遇到右括号时需要有较复杂的类型判断,在写法上相对复杂
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值