LeetCode 20 Valid Parentheses 括号匹配

经典的括号匹配判断问题,由于是比较久远的记忆不太记得怎么做了,稍微想了一下然后搓出来的。

仅有一种括号的情形比较简单,只要记录一下正反括号的数目从左往右扫一遍,保证中间不出现未匹配的右括号即可。但这种方法对于本题的解法在思路上没有贡献,因为如果使用同样的方法,我们会发现两个子串"(({(()"与"(((({)"在匹配到最末位的时候所记录的状态是相同的,而后者很明显是不满足要求的串。

回归本题,一个简单的思路是确认每个括号是否匹配,即对于每个括号求与其相匹配的另一个反括号。根据满足括号匹配的串而言,有着若A是匹配的,则"(A)"也是匹配的这一性质,也就是说若我们从左向右处理的话,每次对于一个左括号'(', 尝试跳过中间的A来确认是否存在右括号')'与之匹配。

最简单的做法,对每一个左括号单独处理,向右扫的过程中无视与自身种类不同的括号,然后使用仅一种括号的做法,直到找到与当前左括号相匹配的右括号为止,然后从原串中将这一对括号去除,循环至整个串清零,则返回true。

时间O(n²),而且会WA,因为无视种类不同的括号,"({)}"这个样例都过不了。

那么使用递归方法求解,每次当前的左括号l找到右括号r时,验证[l+1,r-1]是否合法,解决了上述WA的问题,时间复杂度仍然是O(n²)。

很自然的能够想到改进的思路,既然使用了递归,我们可以做到将左右括号的匹配与中间子串的合法性验证同时进行,方法如下:

构造如下next函数int next(pos)用来求与pos位置的左括号对应的右括号:

  • 对于当前位置pos,确认是否为左括号,若不是则原串不合法
  • 边界处理,检查pos+1是否与当前位置相匹配,若是则返回pos+2
  • 递归调用next(pos+1),即对于"(A)"中去除A的部分,但由于可能存在"(()())"——即A="()()"——以及其它与之类似的情况, 我们判断在next(pos+1)是否与当前左括号匹配时,若不匹配则有i=next(pos+1),并循环使i=next(i),直至求得与pos的左括号对应的i的右括号
  • 若上述i越界,即超出原串长度len,则原串不合法

这样一来串的每个位置都只被访问一次,也就是时间复杂度降到了O(n),而且不仅完成了合法性的检查,还完成了每对括号的匹配。

代码如下:

class Solution {
public:
    bool isleft(char c){
        return c == '(' || c == '[' || c == '{';
    }
    bool isright(char c){
        return c == ')' || c == ']' || c == '}';
    }
    bool ispair(char lc, char rc){
        if (lc == '(' && rc == ')')
            return true;
        if (lc == '[' && rc == ']')
            return true;
        if (lc == '{' && rc == '}')
            return true;
        return false;
    }
    int next(int pos, int len, const string &s){
        if (!isleft(s[pos]) || pos+1 >= len)
            return -1;
        if (ispair(s[pos], s[pos+1]))
            return pos + 2;
        int i = next(pos+1, len, s);
        while(i < len){
            if (i == -1)
                return -1;
            if (ispair(s[pos], s[i]))
                return i + 1;
            i = next(i, len, s);
        }
        return -1;
    }
    bool isValid(string s) {
        int len = s.length();
        int i = 0;
        while(i < len){
            i = next(i, len, s);
            if (i == -1)
                return false;
        }
        return true;
    }
};

最终结果也相当不错:

本题虽然难度为easy,但抛开最简单的O(n²)做法,O(n)的思路个人认为在leetcode这边加个medium还是没有问题的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值