力扣leetcode[678. 有效的括号字符串]题解

题目:
给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:

任何左括号 ( 必须有相应的右括号 )。
任何右括号 ) 必须有相应的左括号 ( 。
左括号 ( 必须在对应的右括号之前 )。

  • 可以被视为单个右括号 ) ,或单个左括号 ( ,或一个空字符串。
    一个空字符串也被视为有效字符串。
    示例 1:

输入: “()”
输出: True
示例 2:

输入: “(*)”
输出: True
示例 3:

输入: “(*))”
输出: True
注意:

字符串大小将在 [1,100] 范围内。

解答:
我用的方法是栈。
刚开始的思路:左括号和下标小于长度一半的星号入栈,右括号和其他星号则当做右括号,操作完成后如果栈的长度为0或1,则返回true,此思路能通过69/83.

class Solution {
public:
    bool checkValidString(string s) {
        int len = s.length();
        cout<<len;
        stack<char> sta;
        for(int i = 0;i<len;i++){
            if(s[i]=='('||(s[i]=='*'&&i<len/2)){ //左括号和下标小于长度一半的星号入栈,右括号和其他星号则当做右括号,操作完成后如果栈的长度为0或1,则返回true,此思路能通过69/83.
            //不能通过的情况为"(((()*())))((()(((()(()))()**(*)())))())()()*",原因是当操作到一定位置后,此时字符串还未遍历的")())()()*"一看就会返回false,但实际为true.
                sta.push(s[i]);
            }
            else{
                if(sta.empty()){
                    sta.push(s[i]);
                }
                else{
                    sta.pop();
                }               
            }
        }
        if(sta.size()==1&&len==1&&s[0]=='(') return false;
        if(sta.size()>1) return false;
        return true;
    }
};

不能通过的情况为"(((()*())))((()(((()(()))()**(*)())))())()()*",原因是当操作到一定位置后,此时字符串还未遍历的")())()()*"一看就会返回false,但实际为true.
但是还没啥解决办法,于是转而用两个栈。分别存储左括号和星号。从左到右遍历字符串,进行如下操作:

  • 如果遇到左括号,则将当前下标存入左括号栈。
  • 如果遇到星号,则将当前下标存入星号栈。
  • 如果遇到右括号,则需要有一个左括号或星号和右括号匹配,由于星号也可以看成右括号或者空字符串,因此当前的右括号应优先和左括号匹配,没有左括号时和星号匹配:
  • 如果左括号栈不为空,则从左括号栈弹出栈顶元素;
  • 如果左括号栈为空且星号栈不为空,则从星号栈弹出栈顶元素;
  • 如果左括号栈和星号栈都为空,则没有字符可以和当前的右括号匹配,返回 false。

遍历结束之后,左括号栈和星号栈可能还有元素。为了将每个左括号匹配,需要将星号看成右括号,且每个左括号必须出现在其匹配的星号之前。当两个栈都不为空时,每次从左括号栈和星号栈分别弹出栈顶元素,对应左括号下标和星号下标,判断是否可以匹配,匹配的条件是左括号下标小于星号下标,如果左括号下标大于星号下标则返回false。
最终判断左括号栈是否为空。如果左括号栈为空,则左括号全部匹配完毕,剩下的星号都可以看成空字符串,此时 s 是有效的括号字符串,返回 true。如果左括号栈不为空,则还有左括号无法匹配,此时 s 不是有效的括号字符串,返回false。

class Solution {
public:
    bool checkValidString(string s) {
        int len = s.length();
        stack<char> sta1;//左括号栈
        stack<char> sta2;//星号栈
        for(int i = 0;i<len;i++){
            if(s[i]=='('){ 
                sta1.push(i);
            }
            else if(s[i]=='*'){
                sta2.push(i);
            }
            else{
                if(!sta1.empty()){
                    sta1.pop();
                }
                else if(sta1.empty()&&!sta2.empty()){
                    sta2.pop();
                }
                else{
                    return false;
                }               
            }
        }
        cout<<sta1.size()<<" "<<sta2.size();
        if(sta1.size()==1&&len==1&&s[0]=='(') return false;
        if(sta2.size()<sta1.size()) return false;//剩的星号比左括号少,肯定false
        else{
            while(!sta1.empty()){
                if(sta1.top()<=sta2.top()){
                    sta1.pop();
                    sta2.pop();
                }
                else return false;
            } 
        }
        return true;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值