Implement regular expression matching with support for ‘.‘
and ‘*‘
.
‘.‘ 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") → false isMatch("aa","aa") → true isMatch("aaa","aa") → false isMatch("aa", "a*") → true isMatch("aa", ".*") → true isMatch("ab", ".*") → true isMatch("aab", "c*a*b") → true
有两种方法, 一种是递归直接匹配,比较好理解,代码简洁。
另一种是DP,时间复杂度小 ,为O(m*n) 其中m是匹配串长度,n是模式串长度。
先说第一种:
设S为匹配串,P为模式串,令i指向匹配串Si,令j指向模式串Pj,判断P[j+1]是否为* 如果不是*,判断S[i] == P[j] ? 如果等于,则递归处理S[i+1] P[j+1],不等于则返回false。如果P[j+1]是*,则需要综合考虑两种情况,一个是*表示前一个字符重复0次,
另一种情况是前一个字符重复 >=1次的情况,并对这两种情况取"或"。 看代码很容易理解的
Runtime: 40 ms
#define ISMATCH(a, b) (a != ‘\0‘ && (a == b || b == ‘.‘)) class Solution { public: bool isMatch(const char *s, const char *p, int i = 0, int j = 0) { if (p[j] == ‘\0‘) return s[i] == ‘\0‘; if (p[j+1] != ‘*‘) return ISMATCH(s[i], p[j]) && isMatch(s, p, i+1, j+1); if (p[j+1] == ‘*‘) { return //0 times isMatch(s, p, i, j+2) || // more times (ISMATCH(s[i], p[j]) && isMatch(s, p, i+1, j)); } return false; } };
第二种方法用的是动态规划,非常巧妙。时间复杂度比较低为O(m*n)
令dp[i][j]表示匹配串S[1..i]是否与模式串P[1..j]匹配。 dp[i][j] = true表示匹配,dp[i][j] = false表示不匹配,状态转移方程可以写成这样:
dp[i][j-2] if P[j] == ‘*‘ 考虑*表示重复前一字符为0次的情况
dp[i][j] = dp[i][j-1] if P[j] == ‘*‘ 考虑*表示重复前一字符为1次的情况(注意这里不用重复字符大于一次的情况,因为其实将来的状态矩阵中已经保存了的, 如dp[i][j]表示重复一次的情况且P[j] = ‘*‘, 那么dp[i+1][j]表示重复2次的情况,
dp[i+2][j]表示重复3次的情况,一次类推.)
dp[i-1][j-1] && S[i] == S[j] if P[j] != ‘*‘
其实只要理解了dp[i][j]表示什么意思,就很好解释了。
代码如下(做了一些优化,本来状态矩阵需要DP[m][n]的空间代价的,但是由于状态转移方程中在获得dp[i][j]时只用到了dp[i][j-2],所以可以只用dp[1..n]来维护状态)
Runtime: 10 ms
#define ISMATCH(a, b) (a == b ||(a != ‘\0‘ && b == ‘.‘)) class Solution { public: bool isMatch(const char *s, const char *p) { int lenS = strlen(s); int lenP = strlen(p); vector<bool> dp(lenS+1, false); dp[0] = true; for (int j = 0; j < lenP; ++j) { if (j+1 < lenP && p[j+1] == ‘*‘) continue; if (p[j] == ‘*‘) { for (int i = 1; i <= lenS; ++i) { dp[i] = dp[i] || (dp[i-1] && ISMATCH(s[i-1], p[j-1])); } } else { for(int i = lenS; i > 0; --i) { dp[i] = dp[i-1] && ISMATCH(s[i-1], p[j]); } dp[0] = false; } } return dp[lenS]; } };
leetcode problem 10 Regular Expression Matching
原文:http://www.cnblogs.com/lysuns/p/4434569.html