leetcode 10 Regular Expression Matching

来源:互联网 发布:paragonntfs for mac 编辑:程序博客网 时间:2024/06/05 18:44
  • 题目地址及大意
  • 回溯法
  • 动态规划方法

题目地址及大意

题目leetcode 10 Regular Expression Matching大意如下:

给定两个字符串,s 与 p,其中 p 有可能包含 . 和 * 两种元素。其中, . 可以代表任何一个字符, * 代表它前面的字符重复 0 次或者更多次。 即 a* 可以代表 空字符, 只含有一个a,含有两个a……

题目刚开始看的时候我连题意都没有很理解,以为 a* 至少包含一个 a,所以题目就看了很久。解答时,看了很多题解,其中有两篇讲解的算是很清楚的,引用如下:
Voidsky博客
Pale Blue Dot博客

回溯法

在这种想法中,我们对 p 字符串从后往前读,如果 p[b]==‘*’,则判断 p[b-1]==s[a] || p[b-1]==’.’ 若以上两种情况中的一种满足,则我们可以认为 字符子串 p[b-1]p[b] 可以表示 s[a], 同时可以将 s 的下标向前移动一位,但即便上述这种情况成立,我们也无法判定 s[a] 确实由 p[b-1]p[b] 表示, 还要根据后续情况加以判断。具体代码如下:

    if(p[b]=='*'){        if(a>=0 && (p[b-1] == '.' || p[b-1]==s[a])){            if(Match(s, a-1, p, b))                return true;            else                return Match(s, a, p, b-2);        }        else            return Match(s, a, p, b-2);    }

p[b] !=‘*’ 情况的判定则要简单许多,这里不再介绍,整体代码如下:

bool Match(string s, int a, string p, int b){    if(b<0){        if(a<0)            return true;        else            return false;    }    if(p[b]!='*'){        if(a>=0 && (p[b]=='.' || p[b]==s[a]))            return Match(s, a-1, p, b-1);        else            return false;    }    if(p[b]=='*'){        if(a>=0 && (p[b-1] == '.' || p[b-1]==s[a])){            if(Match(s, a-1, p, b))                return true;            else                return Match(s, a, p, b-2);        }        else            return Match(s, a, p, b-2);    }}class Solution {public:    bool isMatch(string s, string p) {        return Match(s, s.size()-1, p, p.size()-1);    }};

动态规划方法

在动态规划方法中,设立一个存储类型为 bool 型变量的二维数组, f[m+1][n+1], 其中, m=s.size(); n=p.size();
f[i][j] = true; 代表 s 的前 (i-1) 个字符的子串能够与 p 的前 (j-1) 个字符的子串相匹配。但要注意的是,此时情况可能会比较复杂。
f[0][0] = true; 表示 s 和 p 均为空字符串时,两者是匹配的。
f[i][0] = false; (i>0) 表示 p 为空字符串, s 却不为空的情况下, 两者不匹配。
对于 f[0][j] 的情况,有如下判断方式:

        for(int j=1;j<=n;j++){            if(j>1)                f[0][j] = p[j-1]=='*' && f[0][j-2];        }

对于 f[i][j] (i>0, j>0) 而言,情况就更复杂一些:

        for(int i=1;i<=m;i++){            for(int j=1;j<=n;j++){                if(p[j-1]=='*')                    f[i][j] = f[i][j-2] || (f[i-1][j] && (p[j-2]=='.' || p[j-2]==s[i-1]));      /*f[i][j-2]表示 p[j-2]p[j-1] 子串在当前 s 中不代表任何元素,(f[i-1][j] && (p[j-2]=='.' || p[j-2]==s[i-1])) 表示 p[j-2]p[j-1] 子串在当前 s 中已经代表 s[i-2],但仍可继续代表 s[i-1], 其中它仍可继续代表 s[i-1] 的条件即为 (p[j-2]=='.' || p[j-2]==s[i-1])*/                else                    f[i][j] = f[i-1][j-1] && (s[i-1]==p[j-1] || p[j-1]=='.');            }        }

完整代码如下:

class Solution {public:    bool isMatch(string s, string p) {        int m = s.size();        int n = p.size();        vector<vector<bool>> f(m+1,vector<bool>(n+1, false));        f[0][0] = true;        for(int i=1;i<=m;i++){            f[i][0] = false;        }        for(int j=1;j<=n;j++){            if(j>1)                f[0][j] = p[j-1]=='*' && f[0][j-2];        }        for(int i=1;i<=m;i++){            for(int j=1;j<=n;j++){                if(p[j-1]=='*')                    f[i][j] = f[i][j-2] || (f[i-1][j] && (p[j-2]=='.' || p[j-2]==s[i-1]));                else                    f[i][j] = f[i-1][j-1] && (s[i-1]==p[j-1] || p[j-1]=='.');            }        }        return f[m][n];    }};

0 0
原创粉丝点击