10. Regular Expression Matching
来源:互联网 发布:java list转json 编辑:程序博客网 时间:2024/04/19 08:08
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") → falseisMatch("aa","aa") → trueisMatch("aaa","aa") → falseisMatch("aa", "a*") → trueisMatch("aa", ".*") → trueisMatch("ab", ".*") → trueisMatch("aab", "c*a*b") → true
摘自
https://discuss.leetcode.com/topic/6183/my-concise-recursive-and-dp-solutions-with-full-explanation-in-c
http://blog.csdn.net/fzzying3/article/details/42057935
https://discuss.leetcode.com/topic/40371/easy-dp-java-solution-with-detailed-explanation
public boolean isMatch(String s, String p) { /* 'match' below including . f(i,j) means s where s.len=i matches p where p.len=j f(i,j) = if (p_j-1 != * ) f(i-1, j-1) and s_i-1 matches p_j-1 if (p_j-1 == * ) * matches zero times: f(i,j-2) or * matches at least one time: f(i-1,j) and s_i-1 matches p_j-2 */ if (!p.isEmpty() && p.charAt(0) == '*') { return false; // invalid p } boolean[][] f = new boolean[s.length() + 1][p.length() + 1]; // initialize f(0,0) f[0][0] = true; // f(k,0) and f(0,2k-1) where k>=1 are false by default // initialize f(0,2k) where p_2k-1 = * for any k>=1 for (int j = 1; j < p.length(); j+=2) { if (p.charAt(j) == '*') { f[0][j+1] = f[0][j-1]; } } 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] && isCharMatch(s.charAt(i - 1), p.charAt(j - 1)); } else { f[i][j] = f[i][j - 2] || f[i - 1][j] && isCharMatch(s.charAt(i - 1), p.charAt(j - 2)); } } } return f[s.length()][p.length()];}// no * in pprivate boolean isCharMatch(char s, char p) { return p == '.' || s == p;}
---------------------------------------------------------------------------------------------------------------------------
这里我们采用b[i+1][j+1]代表s[0..i]匹配p[0..j]的结果,结果自然是采用布尔值True/False来表示。
1.因此,首先是对边界进行赋值,显然b[0][0] = true,两个空字符串的匹配结果自然为True
接下来,我们对b[i+1][0]进行赋值,显然对于空的匹配串,b[i+1][0]的数值必须为False
接着,我们对b[0][j+1]进行赋值,其值等于j > 0 && '*' == p[j] && b[0][j - 1],
1.首先是j>0,原因很简单,如果j=0则b[0][1]表示空的原串匹配长度为1的匹配串,无论长度为1的匹配串
为何种字符串,其结果都为false,试想一下,如果匹配串为一个字母字符自不必多说,如果为"."也容易理解,
如果为“*”,则是无效字符串,因为本题要求"*"之前必须要有一个字符,所以长度为1的字符串不可能为“*”;
2.其次'*' == p[j] && b[0][j - 1],如果一个空串和一个匹配串想要匹配成功,那么只有可能是:
p[0..j-2]匹配空串成功且无论p[j-1]是什么p[j]都必须是'*',所以就是'*' == p[j] && b[0][j - 1]
前两个边界赋值结束了之后,接下来就是经典的动态规划递推方程了:
1. 当前匹配串的字符不为’*‘,那么b[i + 1][j + 1] = b[i][j] && ('.' == p[j] || s[i] == p[j]),显然如果当前字符串不为'*',
则我们需要实打实地对s[i]和p[j]进行匹配,因此很自然s[0..i]和p[0..j]的匹配结果取决于s[0..i-1]和p[0..j-1]的
匹配结果与上s[i]和p[j]的匹配结果,因此就造就了上式;
2.若当前匹配串的字符为’*‘,那么b[i + 1][j + 1] = b[i + 1][j - 1] && j > 0 || b[i + 1][j]
|| b[i][j + 1] && j > 0 && ('.' == p[j - 1] || s[i] == p[j - 1]);
其意义为s[0..i]和p[0..j]的匹配结果取决于s[0..i]和p[0..j-2]的匹配结果,意味着我们忽略’*‘不重复,
其次s[0..i]和p[0..j]的匹配结果也可以取决于s[0..i]和p[0..j-1]的匹配结果,意味着我们利用'*'只重复一次,
再次s[0..i]和p[0..j]的匹配结果也可以取决于s[0..i-1]和p[0..j]以及s[i]和p[j-1]的匹配结果,这个是整个递推
表达式当中最难理解的部分,其含义是
如果s[0..i-1]和p[0..j]匹配了,说明当前的’*‘在一个字符之前的原串中已经得到匹配,那么要跟当前这个
字符匹配则只需要判断当前的s[i]和p[j-1]是否匹配即可,显然j必须要大于0,这里其实暗含了’*‘重复多次
的情形,试想s[0..i-1]都和p[0..j]匹配了,那么如果当时的匹配是不重复的匹配,那好,那么这次就是重复
一次的匹配,如果当时是重复n次的匹配,那么经过这次匹配就变成了重复n+1次的匹配了,那么可能有人
要问了既然第三项包含了重复一次的匹配,为何还需要第二项s[0..i]和p[0..j-1]匹配结果,原因是第三项建立
在s[0..i-1]和p[0..j]匹配的基础之上,完全有可能s[0..i-1]和p[0..j]不匹配,然而s[0..i]和p[0..j-1]匹配,应该这么说
’*‘重复一次的匹配有两种,一种是s[0..i-1]和p[0..j-2]匹配再加上当前s[i]和p[j-1]匹配或者s[0..i]和p[0..j-1]匹配
class Solution {public: bool isMatch(const char *s, const char *p) { int i, j; int m = strlen(s); int n = strlen(p); /** * b[i + 1][j + 1]: if s[0..i] matches p[0..j] * if p[j] != '*' * b[i + 1][j + 1] = b[i][j] && s[i] == p[j] * if p[j] == '*', denote p[j - 1] with x, * then b[i + 1][j + 1] is true if any of the following is true * 1) "x*" repeats 0 time and matches empty: b[i + 1][j -1] * 2) "x*" repeats 1 time and matches x: b[i + 1][j] * 3) "x*" repeats >= 2 times and matches "x*x": s[i] == x && b[i][j + 1] * '.' matches any single character */ bool b[m + 1][n + 1]; b[0][0] = true; for (i = 0; i < m; i++) { b[i + 1][0] = false; } // p[0..j - 2, j - 1, j] matches empty if p[j] is '*' and p[0..j - 2] matches empty for (j = 0; j < n; j++) { b[0][j + 1] = j > 0 && '*' == p[j] && b[0][j - 1]; } for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (p[j] != '*') { b[i + 1][j + 1] = b[i][j] && ('.' == p[j] || s[i] == p[j]); } else { b[i + 1][j + 1] = b[i + 1][j - 1] && j > 0 || b[i + 1][j] || b[i][j + 1] && j > 0 && ('.' == p[j - 1] || s[i] == p[j - 1]); } } } return b[m][n]; }};
---------------------------------------------------------------------------------------------------------------------------
Here are some conditions to figure out, then the logic can be very straightforward.
1, If p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1];2, If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1];3, If p.charAt(j) == '*': here are two sub conditions: 1 if p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] //in this case, a* only counts as empty 2 if p.charAt(j-1) == s.charAt(i) or p.charAt(i-1) == '.': dp[i][j] = dp[i-1][j] //in this case, a* counts as multiple a or dp[i][j] = dp[i][j-1] // in this case, a* counts as single a or dp[i][j] = dp[i][j-2] // in this case, a* counts as empty
public boolean isMatch(String s, String p) { if (s == null || p == null) { return false; } boolean[][] dp = new boolean[s.length()+1][p.length()+1]; dp[0][0] = true; for (int i = 0; i < p.length(); i++) { if (p.charAt(i) == '*' && dp[0][i-1]) { dp[0][i+1] = true; } } for (int i = 0 ; i < s.length(); i++) { for (int j = 0; j < p.length(); j++) { if (p.charAt(j) == '.') { dp[i+1][j+1] = dp[i][j]; } if (p.charAt(j) == s.charAt(i)) { dp[i+1][j+1] = dp[i][j]; } if (p.charAt(j) == '*') { if (p.charAt(j-1) != s.charAt(i) && p.charAt(j-1) != '.') { dp[i+1][j+1] = dp[i+1][j-1]; } else { dp[i+1][j+1] = (dp[i+1][j] || dp[i][j+1] || dp[i+1][j-1]); } } } } return dp[s.length()][p.length()];}
- 10. Regular Expression Matching
- 10.Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 10. Regular Expression Matching
- 做10年Windows程序员与做10年Linux程序员的区别
- hdu 1667 The Rotation Game(2004 Asia Regional Shanghai)
- 翻页功能测用例设计
- 常量与变量以及在内存中存储形式
- POJ 2752 Seek the Name, Seek the Fame
- 10. Regular Expression Matching
- opencv中的各种滤波函数
- 简单导航
- 线程共享方式
- 关于浏览器兼容性的博客锦集
- 金庸笔下的编程秘籍
- 树(5)二叉树层次遍历的应用
- 菜鸟必看css学习小技巧怎么实现三角形
- libboost一些常用库(数据结构,迭代器,算法及字符串)