leetcode 10 Regular Expression Matching(Dynamic Programming)

来源:互联网 发布:百度网络硬盘登陆 编辑:程序博客网 时间:2024/06/07 13:21

题意:

'.' Matches any single character.'*' Matches zero or more of the preceding element.The matching should cover the entire input string (not partial).The function prototype should be:bool isMatch(const char *s, const char *p)Some examples:isMatch("aa","a") → falseisMatch("aa","aa") → trueisMatch("aaa","aa") → falseisMatch("aa", "a*") → trueisMatch("aa", ".*") → trueisMatch("ab", ".*") → trueisMatch("aab", "c*a*b") → true

设左边字符串为s,右边字符串为p。判断是否可以用右边的字符串完全匹配左边的字符串。

其中‘.’可以代表任何一个单个字符,‘*’代表其之前的字符有任意个(例如"c*"可以代表 没有c,1个c,2个c...)

倒数第二个样例解释: “.*”用来代表“..”,“..”可以完全匹配“ab”

倒数第一个样例解释:“c*a*b”中“c*”代表空字符(0个c),“a*”代表“aa”


解决方法:

1.暴力深搜

刚开始我们需要解决的问题是:

判断s和p从各自的起始位置s[0] p[0]开始,直到他们的结束位置s[s.length()-1],p[p.length()-1]为止是否能完全匹配。

假设现在已经匹配到了s[i],p[j](二者之前的子串完全匹配),现在问题转化成:

判断s和p从各自的起始位置s[i] p[j]开始,直到他们的结束位置s[s.length()-1],p[p.length()-1]为止是否能完全匹配。

以上是状态转化。


由于p中字符"*" "."的存在,要考虑到的问题多了一些:

(1)当前状态起始位置为s[i] p[j],p[j+1] != '*':若s[i] == p[j], 状态转移到起始位置为s[i+1] p[j+1];若s[i] != p[j],返回false。

(2)当前状态起始位置为s[i] p[j],p[j+1] == '*':

因为*的特殊功能,所以p[j]这个字符,可以当作空字符(不存在),这样状态就转换为:状态起始位置为s[i] p[j+2]

    可以当作1个字符:若s[i] == p[j], 状态转移到起始位置为s[i+1] p[j+2];

    可以当作2个字符:若s[i] == p[j]且s[i+1] == p[j], 状态转移到起始位置为s[i+2] p[j+2];

    可以当作3个字符:若s[i] == p[j]且s[i+1] == p[j]且s[i+2] == p[j], 状态转移到起始位置为s[i+3] p[j+2];

    。。。。。。

代码:

class Solution {public:    bool dfs(string s, string p, int i, int j){        if(j==p.length())            return i==s.length();        //p[j+1] != '*';        if(j==p.length()-1 || p[j+1]!='*')        {            if(i==s.length()|| s[i]!=p[j] && p[j]!='.')                return false;            else                return dfs(s,p,i+1,j+1);        }        //p[j+1]=='*'        while(i<s.length() && (p[j]=='.' || s[i]==p[j]))        {            if(dfs(s,p,i,j+2))                return true;            i++;        }        return dfs(s,p,i,j+2);    }public:    bool isMatch(string s, string p) {        return dfs(s, p, 0, 0);    }};


这个方法的运行时间为150-190ms;加上状态记录数组,我认为时间复杂度变成了O(n^2),但是运行时间(82ms)减少的幅度不太明显(相比动态规划做法来说)。我不是很明白为什么时间减少不太明显,关于这个问题,非常感谢大家能提供一些意见和建议。以下是加上状态记录的代码:


class Solution {    bool vis[1005][1005];    bool res[1005][1005];public:    bool dfs(string s, string p, int i, int j){        if(vis[i][j]) return res[i][j];        vis[i][j] = true;        if(j==p.length())            return res[i][j] = (i==s.length());        if(j==p.length()-1 || p[j+1]!='*')        {            if(i==s.length()|| s[i]!=p[j] && p[j]!='.'){                return res[i][j] = false;            }            else{                return res[i][j] = dfs(s,p,i+1,j+1);            }        }        //p.charAt(j+1)=='*'        while(i<s.length() && (p[j]=='.' || s[i]==p[j]))        {            if(dfs(s,p,i,j+2)){                return res[i][j] = true;            }            i++;        }        return res[i][j] = dfs(s,p,i,j+2);    }public:    bool isMatch(string s, string p) {        //memset(vis, false, sizeof(vis));        return dfs(s, p, 0, 0);    }};



2.动态规划

/**         * f[i][j]: if s[0..i-1] matches p[0..j-1]         * if p[j - 1] != '*'         *      f[i][j] = f[i - 1][j - 1] && s[i - 1] == p[j - 1]         * if p[j - 1] == '*', denote p[j - 2] with x         *      f[i][j] is true iff any of the following is true         *      1) "x*" repeats 0 time and matches empty: f[i][j - 2]         *      2) "x*" repeats >= 1 times and matches "x*x": s[i - 1] == x && f[i - 1][j]         * '.' matches any single character         */

这是我看到的一个思路,感觉特别好。

f[i][j]状态定义为s的前i 个字符 与 p的前j个字符是否完全匹配:true/false

(1)p[j-1] != '*'时,直接根据f[i-1][j-1]和s[i-1] p[j-1]转移状态

if p[j - 1] != '*'      f[i][j] = f[i - 1][j - 1] && s[i - 1] == p[j - 1]

(2)p[j-1] == '*'时,

p[j-2]可以当作空字符,此时f[i][j]状态由f[i][j-2]状态直接得到;

p[j-1]可以当作>=1个字符此时若s[i-1] == p[j-2]只需要f[i-1][j]为true,s[i-1]这个字符就可以用‘*’重复出来的p[j-2]来匹配(而不用管之前这个p[j-1]已经重复造出来过几个p[j-2])


代码:为了加深自己的理解,自己用java写了一下。

public class Solution {    public static boolean isMatch(String s, String p) {        boolean[][] f = new boolean[s.length()+1][p.length()+1];        f[0][0] = true;        boolean tmp = true;        for(int j = 1; j <= p.length(); j++){            if(tmp && p.charAt(j-1) != '*' && j < p.length() && p.charAt(j) != '*') tmp = false;            if(tmp && j == p.length() && p.charAt(j-1) != '*') tmp = false;             f[0][j] = tmp;        }        for(int i = 1; i <= s.length(); i++){            for(int j = 1; j <= p.length(); j++){                if(p.charAt(j-1) != '*'){                    f[i][j] = f[i-1][j-1] && (s.charAt(i-1) == p.charAt(j-1) || p.charAt(j-1) == '.');                }                else{                    f[i][j] = f[i][j-2] || ((s.charAt(i-1) == p.charAt(j-2) || p.charAt(j-2) == '.') && f[i-1][j]);                }            }        }        //System.out.println(f[1][2]);        return f[s.length()][p.length()];    }}



希望对大家有所帮助,欢迎大家将任何问题在回复区讨论。



0 0
原创粉丝点击