• 剑指 Offer 19. 正则表达式匹配 (偏难)- 7月3日


    题目

    我的思路

    我的解决思路是深搜递归,可是需要注意时间复杂度,不同的深搜3^n与2^n的复杂度差别还是蛮大的。

    下面结合官方题解,阐述一下两种思路:

    思路一:深搜递归

    时间复杂度是2^n,空间复杂度是n(可能同时存在n次递归调用层)。

    class Solution {
    public:
        bool isMatch(string s, string p) {
            if(p.empty()) return s.empty();
            if(p[1] == '*'){
                return isMatch(s, p.substr(2)) || (!s.empty() && (s[0] == p[0] || p[0] == '.')) && isMatch(s.substr(1), p);
            }
            else{
                return !s.empty() && (s[0] == p[0] || p[0] == '.') && (isMatch(s.substr(1), p.substr(1)));
            }
        }
    };
    
    作者:jarvis1890
    链接:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof/solution/zheng-ze-biao-da-shi-pi-pei-di-gui-qiu-jie-by-jarv/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    思路二:动态规划(神!)

     
    class Solution {
        public boolean isMatch(String A, String B) {
            int n = A.length();
            int m = B.length();
            boolean[][] f = new boolean[n + 1][m + 1];
    
            for (int i = 0; i <= n; i++) {
                for (int j = 0; j <= m; j++) {
                    //分成空正则和非空正则两种
                    if (j == 0) {
                        f[i][j] = i == 0;
                    } else {
                        //非空正则分为两种情况 * 和 非*
                        if (B.charAt(j - 1) != '*') {
                            if (i > 0 && (A.charAt(i - 1) == B.charAt(j - 1) || B.charAt(j - 1) == '.')) {
                                f[i][j] = f[i - 1][j - 1];
                            }
                        } else {
                            //碰到 * 了,分为看和不看两种情况
                            //不看
                            if (j >= 2) {
                                f[i][j] |= f[i][j - 2];
                            }
                            //
                            if (i >= 1 && j >= 2 && (A.charAt(i - 1) == B.charAt(j - 2) || B.charAt(j - 2) == '.')) {
                                f[i][j] |= f[i - 1][j];
                            }
                        }
                    }
                }
            }
            return f[n][m];
        }
    }
    
    作者:jerry_nju
    链接:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof/solution/zhu-xing-xiang-xi-jiang-jie-you-qian-ru-shen-by-je/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    时间复杂度是m*n,空间复杂度也是m*n

    我的实现

    class Solution {
    public:
        //动态规划:f[i][j]表示主串的前i+1(0~i)个字符能否由模式串的前j+1(0~j)个字符匹配
        /*
        模式串p[j]是'*',那么f[i][j]=f[i][j-2]||f[i][j-1]||(s[i]==s[i-1]&&(f[i-1][j-1]||f[i-1][j]))||(p[j-1]=='.'&&(f[i-1][j-1]||f[i-1][j]))
        模式串p[j]是'.',那么f[i][j]=f[i-1][j-1];
        模式串p[j]是others,那么f[i][j]=f[i-1][j-1]&&s[i]==p[j]
        */
        bool isMatch(string s, string p) {
            //给模式字符串去重
            //bool[][] f = new bool[][](s.size()+1,p.size()+1);
            bool f[s.size()+1][p.size()+1];
            f[0][0]=true;
            //return f[0][0];
            for(int j = 1;j<=p.size();j++){
                if(j==1)f[0][j]=false;
                else if(j>=2){
                    if(p[j-1]=='*'){
                        f[0][j] = f[0][j-2]||f[0][j-1];
                        //cout<<f[0][j]<<"	j:"<<j<<endl;
                    }else{
                        f[0][j] = false;
                    }
                }
            }
            for(int i = 1;i<=s.size();i++){
                f[i][0]=false;
            }
            
            for(int i = 1;i<=s.size(); i++){
                for(int j = 1; j<=p.size();j++){
                    //cout<<"check???"<<endl;
                    if(p[j-1]=='*'){
                        if(i==1)f[i][j]=f[i][j-2]||f[i][j-1]||(p[j-2]=='.'&&(f[i-1][j-1]||f[i-1][j]));else
                        f[i][j]=f[i][j-2]||f[i][j-1]||(s[i-2]==s[i-1]&&s[i-1]==p[j-2]&&(f[i-1][j-1]||f[i-1][j]))||(p[j-2]=='.'&&(f[i-1][j-1]||f[i-1][j]));
                    }else if(p[j-1]=='.'){
                        f[i][j]=f[i-1][j-1];
                    }else {
                        f[i][j] = f[i-1][j-1]&&s[i-1]==p[j-1];
                    }
                }
            }
            //cout<<f[0][0]<<f[0][1]<<f[0][2]<<"
    "<<f[1][0]<<f[1][1]<<f[1][2]<<"
    "<<f[2][0]<<f[2][1]<<f[2][2]<<endl;
            int a = s.size();
            int b = p.size();
            return f[a][b];
        }
    };
    /*
    我的做法通过了部分测试用例,但是时间复杂度太高了,遇到仅最后一个字符不能匹配,而的字符前面存在多种匹配方式的用例,会发生超时。
    比如:"aaaaaaaaaab" "a*a*a*a*a*a*a*a*a*a*c"
    经过改进(在深搜递归出口处增加一点判断),深搜的复杂度从3^n降到了2^n通过了所有用例。
    
    深搜
    每次读取两个字符,如果被读取的第二个字符不是*那么回退一个字符。
    6种情况:第一个字符是否是. ,第二个字符是否是* ,第一个字符是否与待匹配字符相同。
    否否否,返回false;
    否否是,continue;
    `否是否,continue;
    `否是是,深搜continue/深搜指针再回退一个字符continue;
    是否,continue;
    是否,不存在(continue);
    `是是,深搜指针再回退一个字符,并把‘.’改成待匹配字符,continue
    class Solution {
    public:
        bool search(string &s,string &p,int s_it,int p_it){
            if(s.size()==s_it ){
                if(p_it==p.size())return true;
                }
            if(p.size()==p_it)return false;
            cout<<"s:"<<s[s_it]<<"	p:"<<p[p_it]<<endl;
            if(p.size()-1>p_it){//如果存在两个未匹配的模式字符
                if(p[p_it+1]=='*'){//如果第二个字符是*
                    if(p[p_it]=='.'){//是是
                        if(search(s,p,s_it+1,p_it+2)==true)return true;
                        if(search(s,p,s_it+1,p_it)==true)return true;
                        if(search(s,p,s_it,p_it+2)==true)return true;
                    }else{
                        if(p[p_it] == s[s_it]){//否是是
                            if(search(s,p,s_it+1,p_it+2)==true)return true;
                            if(search(s,p,s_it+1,p_it)==true)return true;
                            if(search(s,p,s_it,p_it+2)==true)return true;
                        }else{//否是否
                        return search(s,p,s_it,p_it+2);
                        }
                    }
                }
            }
            {//如果只有一个未匹配的模式字符 or 如果第二个字符不是*
                if(p[p_it]!='.'){
                    if(p[p_it]!=s[s_it]) //否否否
                        return false;
                    else//否否是
                        return search(s,p,s_it+1,p_it+1);
                }else{//是否
                    return search(s,p,s_it+1,p_it+1);
                }
            }
        }
        bool isMatch(string s, string p) {
            //给模式字符串去重
            for(int i = 0;i<s.size();i++){
            }
            return search(s,p,0,0);
        }
    };
    
    下面这个深搜不会发生超时
    class Solution {
    public:
        bool search(string &s,string &p,int s_it,int p_it){
            if(s.size()==s_it ){
                if(p_it==p.size())return true;
                if((p.size()-p_it)%2!=0){
                    return false;
                }else{
                    int k;
                    for(k=p_it+1;k<p.size();k+=2){
                        if(p[k]!='*')return false;
                    }
                    return true;
                }
                }
            if(p.size()==p_it)return false;
            //cout<<"s:"<<s[s_it]<<"	p:"<<p[p_it]<<endl;
            if(p.size()-1>p_it){//如果存在两个未匹配的模式字符
                if(p[p_it+1]=='*'){//如果第二个字符是*
                    if(p[p_it]=='.'){//是是
                        //if(search(s,p,s_it+1,p_it+2)==true)return true;
                        if(search(s,p,s_it+1,p_it)==true)return true;
                        if(search(s,p,s_it,p_it+2)==true)return true;
                    }else{
                        if(p[p_it] == s[s_it]){//否是是
                            //if(search(s,p,s_it+1,p_it+2)==true)return true;
                            if(search(s,p,s_it+1,p_it)==true)return true;
                            if(search(s,p,s_it,p_it+2)==true)return true;
                        }else{//否是否
                        return search(s,p,s_it,p_it+2);
                        }
                    }
                }
            }
            {//如果只有一个未匹配的模式字符 or 如果第二个字符不是*
                if(p[p_it]!='.'){
                    if(p[p_it]!=s[s_it]) //否否否
                        return false;
                    else//否否是
                        return search(s,p,s_it+1,p_it+1);
                }else{//是否
                    return search(s,p,s_it+1,p_it+1);
                }
            }
        }
        bool isMatch(string s, string p) {
            //给模式字符串去重
            return search(s,p,0,0);
        }
    };
    
    */

    拓展学习

    加快速度,刻意练习速度!一定要在上午12点之前弄完每日一题

  • 相关阅读:
    深入理解系统调用
    基于mykernel 2.0编写一个操作系统内核
    如何评测一个软件工程师的计算机网络知识水平与网络编程技能水平?
    如何评测软件工程知识技能水平?
    深入理解TCP的三次握手及其源代码
    Socket与系统调用深度分析
    未来的图书会是什么样子?
    构建调试Linux内核网络代码的环境MenuOS系统
    Python笔记005-神奇的+=
    Python笔记004-元组的拆包和命名元组
  • 原文地址:https://www.cnblogs.com/BoysCryToo/p/13426614.html
Copyright © 2020-2023  润新知