LeetCode OJ10 Regular Expression Matching
2015-10-12 21:53
429 查看
LeetCode OJ10 Regular Expression Matching
‘.’ 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
if(str1[0]==str2[0])讨论str2[1]==′∗′的情形if(str1[0]!=str2[0]讨论str[2]==′.∗′,′x∗′的情形\begin{equation}
if (str1[0] == str2[0]) \\
讨论 str2[1] == '*' 的情形 \\
if (str1[0] != str2[0] \\
讨论 str[2] == '.*', 'x*'的情形
\end{equation}
Just to build a DP table checked, where checked[i][j] indicates whether s[0..i-1] matches with p[0..j-1]. The recursive relationship is as below: To match with the empty string s[0..0] (i.e. to make checked[0][j]), P[0..j-1] has to meet: p[j-1]==’*’ (to cancel p[j-2]) and checked[0][j-2] == true; To match with the string s[0..i-1] (i.e. to make checked[i][j]), P[0..j-1] has to meet:
if p[j-1] ==’*’, then j must be larger than 1 (j>1) and
checked[i][j-2] (i.e. p[j-2] cancelled by ‘*’)
checked[i-1][j] && (s[i-1] ==p[j-2] || p[j-2] ==’.’) (s[i-1] matches with p[j-2] or ‘.’, )
if p[j-1] !=’*’, checked[i-1][j-1] && (s[i-1] ==p[j-1] || p[j-1] ==’.’)(i.e. s[i-1] matches with p[j-1] or ‘.’)
题目要求
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
解题思路
基本思路, 就是动态规划if(str1[0]==str2[0])讨论str2[1]==′∗′的情形if(str1[0]!=str2[0]讨论str[2]==′.∗′,′x∗′的情形\begin{equation}
if (str1[0] == str2[0]) \\
讨论 str2[1] == '*' 的情形 \\
if (str1[0] != str2[0] \\
讨论 str[2] == '.*', 'x*'的情形
\end{equation}
代码展示
mycode 1
这是我们早先写的代码, 用时32msclass Solution { public: bool isMatch_(char * ps, int m, char * pp, int n) { if (n == 0) return m == 0 ? true : false; if (n == 1) { if (m == 1 && (*ps == *pp || *pp == '.')) return true; return false; } if (m == 0) { if (pp[1] == '*') return isMatch_(ps, m, pp + 2, n - 2); return false; } // n > 1 if (pp[1] != '*') { if (ps[0] == pp[0] || pp[0] == '.') return isMatch_(ps + 1, m - 1, pp + 1, n - 1); return false; } if (pp[1] == '*') { if (ps[0] == pp[0]) return isMatch_(ps + 1, m - 1, pp, n) || isMatch_(ps, m, pp + 2, n - 2); if (ps[0] != pp[0] && pp[0] != '.') return isMatch_(ps, m, pp + 2, n - 2); // .* if (ps[0] != pp[0] && pp[0] == '.') return isMatch_(ps, m, pp + 2, n - 2) || isMatch_(ps + 1, m - 1, pp, n); } } bool isMatch(string s, string p) { return isMatch_(&s[0], s.size(), &p[0], p.size()); } };
mycode2
这段代码, 是今天 2015. 10. 12 写下的, 思路比较清晰, 但是运行下来时间用了 648 ms, 是之前的解法的20倍之多,效率太低, 主要原因是, 这里使用了各种string的拷贝构造, 带来很大的消耗class Solution { public: bool isMatch(string s, string p) { if (p.size() == 0) return s.size() == 0 ? true : false; else if (p.size() == 1){ if (s.size() == 0) return false; else if (p[0] != s[0] && p[0] != '.') return false; /* else if (p[0] != s[0] && p[0] == '.') return isMatch(s.substr(1), p.substr(1));*/ else /*if (p[0] == s[0])*/ return isMatch(s.substr(1), p.substr(1)); }else{ if (s.size() == 0) return p[1] == '*' ? isMatch(s, p.substr(2)) : false; if (s[0] == p[0]){ if (p[1] != '*'){ return isMatch(s.substr(1), p.substr(1)); }else{ return isMatch(s.substr(1), p) || isMatch(s, p.substr(2)); } }else{ if (p[0] == '.' && p[1] == '*'){ return isMatch(s.substr(1), p) || isMatch(s, p.substr(2)); }else if (p[0] == '.' && p[1] != '*'){ return isMatch(s.substr(1), p.substr(1)); }else if (p[0] != '.' && p[1] == '*'){ return isMatch(s, p.substr(2)); }else{ return false; } } } } };
mycode3
在分析code2的基础上, 我们试图利用string的移动构造, 改进程序的效率, 运行时间为 396ms, 提升不是很大class Solution { public: bool _isMatch(string && s, string && p) { if (p.size() == 0) return s.size() == 0 ? true : false; else if (p.size() == 1){ if (s.size() == 0) return false; else if (p[0] != s[0] && p[0] != '.') return false; /* else if (p[0] != s[0] && p[0] == '.') return _isMatch(s.substr(1), p.substr(1));*/ else /*if (p[0] == s[0])*/ return _isMatch(s.substr(1), p.substr(1)); }else{ if (s.size() == 0) return p[1] == '*' ? _isMatch(std::move(s), p.substr(2)) : false; if (s[0] == p[0]){ if (p[1] != '*'){ return _isMatch(s.substr(1), p.substr(1)); }else{ return _isMatch(s.substr(1), std::move(p)) || _isMatch(std::move(s), p.substr(2)); } }else{ if (p[0] == '.' && p[1] == '*'){ return _isMatch(s.substr(1), std::move(p)) || _isMatch(std::move(s), p.substr(2)); }else if (p[0] == '.' && p[1] != '*'){ return _isMatch(s.substr(1), p.substr(1)); }else if (p[0] != '.' && p[1] == '*'){ return _isMatch(std::move(s), p.substr(2)); }else{ return false; } } } } bool isMatch(string s, string p){ return _isMatch(std::move(s), std::move(p)); } };
大神们的代码
demo 1
大神考虑的方式和我么不太一样, 他主要使用 判断 ‘*’, 并使用了带记录的DP算法, 效率明显比我们的要高!!!class Solution { public: bool isMatch(string s, string p) { if (p.empty()) return s.empty(); if ('*' == p[1]) // x* matches empty string or at least one character: x* -> xx* // *s is to ensure s is non-empty return (isMatch(s, p.substr(2)) || !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p)); else return !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p.substr(1)); } }; class Solution { public: bool isMatch(string s, string p) { /** * 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 */ int m = s.size(), 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; // p[0.., j - 3, j - 2, j - 1] matches empty iff p[j - 1] is '*' and p[0..j - 3] matches empty for (int j = 1; j <= n; j++) f[0][j] = j > 1 && '*' == 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 - 1][j - 1] && (s[i - 1] == p[j - 1] || '.' == p[j - 1]); else // p[0] cannot be '*' so no need to check "j > 1" here f[i][j] = f[i][j - 2] || (s[i - 1] == p[j - 2] || '.' == p[j - 2]) && f[i - 1][j]; return f[m] ; } };
demo 2
4ms 版本Just to build a DP table checked, where checked[i][j] indicates whether s[0..i-1] matches with p[0..j-1]. The recursive relationship is as below: To match with the empty string s[0..0] (i.e. to make checked[0][j]), P[0..j-1] has to meet: p[j-1]==’*’ (to cancel p[j-2]) and checked[0][j-2] == true; To match with the string s[0..i-1] (i.e. to make checked[i][j]), P[0..j-1] has to meet:
if p[j-1] ==’*’, then j must be larger than 1 (j>1) and
checked[i][j-2] (i.e. p[j-2] cancelled by ‘*’)
checked[i-1][j] && (s[i-1] ==p[j-2] || p[j-2] ==’.’) (s[i-1] matches with p[j-2] or ‘.’, )
if p[j-1] !=’*’, checked[i-1][j-1] && (s[i-1] ==p[j-1] || p[j-1] ==’.’)(i.e. s[i-1] matches with p[j-1] or ‘.’)
class Solution { public: bool isMatch(string s, string p) { int sSize = s.size(), pSize = p.size(), i, j; bool checked[sSize+1][pSize+1]; // fill_n(&matched[0][0], (sSize+1)*(pSize+1), false); for(j=2, checked[0][0]=true, checked[0][1]= false; j<=pSize; ++j) // match s[0..0] checked[0][j] = p[j-1] == '*'? checked[0][j-2] : false; for(i=1; i<=sSize; ++i) for(j=1, checked[i][0]=false; j<=pSize; ++j) { if(p[j-1]=='*') // case (1) checked[i][j] = (j>1) && ( checked[i][j-2] || ( ( checked[i-1][j]) && (s[i-1]== p[j-2] || p[j-2] == '.')) ); else // case (2) checked[i][j] = checked[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.'); } return checked[sSize][pSize]; } };
demo 3
这个使用的方法, 和我们写的第一段代码十分类似class Solution { private: bool helper(const string &s, const string &p, int sS, int pS) { int sSize = s.size(), pSize = p.size(), i, j; if(pS==pSize) return sS ==sSize; // if p goes to its end, then only if s also goes to its end to return true; if(p[pS+1]!='*') { if( sS<sSize && (p[pS]==s[sS] || p[pS] == '.')) return helper(s, p, sS+1, pS+1); } else { if(helper(s, p, sS,pS+2)) return true; while(sS<sSize && (p[pS]==s[sS] || p[pS] == '.')) if(helper(s,p, ++sS, pS+2)) return true; } return false; } public: bool isMatch(string s, string p) { helper(s, p, 0, 0); } };
相关文章推荐
- spring读写分离 - 事务配置篇(转)
- [LeetCode]题解(python):024-Swap Nodes in Pairs
- 五大主流数据库模型
- 【黑马程序员】【OC语言】多态
- iOS_开发_工具_mac下加密文件
- CVPR 2015 Oral概览 - 第二天下午
- 黑马程序员——OC---MRC里的循环retain问题
- C#文本写入文件,追加写入文件
- 圍鼠三日
- poj_2553 强连通分支&出度为0的点
- 【黑马程序员】【OC语言】继承
- vert.x中的buffer简介
- Spring 事情具体详尽的解释
- Struts2-配置struts.xml
- android 的 Testing Support Library 测试支持包(库)
- Max Points on a Line
- TCP和UDP
- ZOJ 3911 Prime Query(线段树区间更新+点更新)
- UVA11456--dp,LIS
- html5 canvas画板