[Leetcode P10]Regular Expression Matching 正则匹配

来源:互联网 发布:淘宝跳蚤街与闲鱼 编辑:程序博客网 时间:2024/06/12 01:31

总共用了两种解法,一种是我自己递归求解的,效率很低,边界条件很难理清楚,代码很长,第二种是DP解法,把递归的子问题的解存到一个数组里,代码很短。
1. 递归解法
主要想法是根据当前的正则表达式,来决定接下去如何匹配,我们可以用两个字符串的子串去匹配,麻烦的是,可能相同的子字符串被求解了很多遍,特别是.*对应的字符串需要循环求解。写完这个解法以后,我很自然地就知道可以用DP递归求解了,不过边际条件比较难确定,我们可以

struct match{    bool isMatch;    char c;    int pos;};class Solution {public:    vector<match> matchArray;    string reg;    bool Match(string s, int current){        for (int i = 0; i < s.length(); ++i)        {            if (current >= matchArray.size())            {                return false;            }            match m = matchArray[current];            if (m.c == '.' && m.isMatch == true)            {                if (current == matchArray.size() - 1)                {                    return true;                }                else                {                    while(matchArray[current].isMatch){                        current++;                        if (current >= matchArray.size())                        {                            return true;                        }                    }                    char c = matchArray[current].c;                    bool isMatch = matchArray[current].isMatch;                    for (int j = i; j < s.length(); ++j)                    {                        if (Match(s.substr(j), current))                        {                            return true;                        }                    }                    return false;                }            }            else if (m.c == '.')            {                current++;            }            else if (m.isMatch == true)            {                if (Match(s.substr(i), current + 1))                {                    return true;                }                else if (s[i] != m.c)                {                    return false;                }                while(s[i] == m.c){                    i++;                    if (Match(s.substr(i), current + 1))                    {                        return true;                    }                }                return false;            }            else if (m.c != s[i])            {                return false;            }            else{                current++;            }        }        for (int i = current; i < matchArray.size(); ++i)        {            if (matchArray[i].isMatch == false)            {                return false;            }        }        return true;    }    bool isMatch(string s, string p) {        reg = p;        if (p.length() == 0 && s.length() == 0)        {            return true;            }        else if (p.length() == 0 /*|| s.length() == 0*/)        {            return false;        }        for (int i = 0; i < p.length(); ++i)        {            match m;            m.pos = i;            m.c = p[i];            if (i + 1 < p.length() && p[i+1] == '*')            {                m.isMatch = true;                i++;            }            else{                m.isMatch = false;            }            matchArray.push_back(m);        }        return Match(s, 0);    }};   
  1. DP解法
    我们可以顺其自然地记录子问题的解,代码里注释比较全。
// 既然可以递归求解,那应该可以记录子节点的情况,做DP// 我们选择的是p的长度为j的子串是否匹配s的长度为i的子串class Solution {public:    bool dp[100][100];    bool isMatch(string s, string p) {        dp[0][0]=true;        for (int i = 1; i <= s.length(); ++i)        {            dp[i][0]=false;        }        int len1 = s.length();        int len2 = p.length();        for (int i = 0; i <= len1; ++i)        {            // 注意i=0对应的是s是空串的情况            for (int j = 1; j <= len2; ++j)            {                // 同样的j=0对应的是p=0的情况,而且我们已经初始化过了                // i,j对应的是字符串的                if (p[j-1] == '*')                {                    if (p[j-2]=='.' || (i>0&&p[j-2]==s[i-1]))                    {                        // p_j-2可以匹配s的结尾,那么只需要匹配情况和长度为i-1的s一样就可以了                        // 主要是x*可以匹配0/1个:                        // 1 如果p可以匹配s,则px*一定匹配sx                        // 2 如果p不可以匹配s,则:                        //     2.1 如果希望px*匹配sx,那么说明x*匹配的不是单一的x:                        //          2.1.1 x*匹配的是空,则p匹配sx也就是dp[i][j-2]=true                        //          2.1.2 x*匹配的是xxxxx,做了k次匹配,则px*一定也可以匹配sxxxx(k-1个x)                        //                ,也就是dp[i-1][j]=true(还要求i>0)                        //     2.2 匹配的情况只有以上两种,不匹配的话取反就可以了,而dp[i][j-2]已经做了相应的记录,直接用就好                        // 而且因为*不会出现在p开头,所以j>=2                        // 这里可能会出现一些误解,只要想清楚p[j-2]对应的长度是j-1,dp[i][j-2]对应的长度是j-2就可以                        dp[i][j]=(i>0&&dp[i-1][j])||dp[i][j-2];                    }                    else{                        // 如果不能匹配结尾,说明x*毫无作用,它做了0次匹配,对应的是2.1.1的情况                        dp[i][j]=dp[i][j-2];                    }                }                else if (i>0 && (p[j-1]=='.' || p[j-1]==s[i-1]))                {                    // 这里如果p可以匹配s,那么p.可以匹配sx,如果p不可以匹配s,那么p.也不可以匹配sx                    // px和sx是同理的                    dp[i][j]=dp[i-1][j-1];                }                else{                    // 其他情况下,也就是说,pa不匹配sb,那么我们暂时让它等于false                    // 这个条件,我在yy的时候,一直在想p有.*的情况,好像理不清楚的样子                    // 其实很简单,p'.*a和sb一样是不匹配的,p'.*其实在第一步讨论过了                    dp[i][j]=false;                }            }        }        return dp[len1][len2];    }};
阅读全文
0 0