您的位置:首页 > 其它

LeetCode OJ10 Regular Expression Matching

2015-10-12 21:53 429 查看
LeetCode OJ10 Regular Expression Matching

题目要求

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

这是我们早先写的代码, 用时32ms

class 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);
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: