您的位置:首页 > 其它

LeetCode 10 - Regular Expression Matching

2015-12-21 16:22 429 查看
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


DP Code

class Solution
{
public:
/* dp[i][j]:
* true  -> s[0...i-1] matches p[0...j-1]
* flase -> otherwise
*
* (1) trivial string
* p[i][j] = p[i-1][j-1], if p[j-1] != '*' && (s[i-1] == p[j-1] || p[j-1] == '.')
* (2) x* matches empty string
* p[i][j] = p[i][j-2], if p[j-1] == '*'
* (3) x* -> xx*, i.e. x repeats for at least 1 times
* p[i][j] = p[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.'), if p[j-1] == '*'
*/
bool isMatch(string s, string p)
{
int m = s.length(), n = p.length();

vector<vector<bool> > dp(m+1, vector<bool>(n+1, false));
dp[0][0] = true; // initialization

for (int i = 0; i <= m; i++)
for (int j = 1; j <= n; j++)
if (p[j-1] == '*')
dp[i][j] = dp[i][j-2] || i > 0 && dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.');
else
dp[i][j] = i > 0 && dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.');

return dp[m]
;
}
};

Runtime: 20 ms



Backtrack Code

struct backtrackPoint
{
int stringIndex, patternIndex;

backtrackPoint() { stringIndex = patternIndex = 0; }
backtrackPoint(int stringIndex, int patternIndex): stringIndex(stringIndex), patternIndex(patternIndex){ }
};

struct pattern
{
string s;
pattern(const string& s): s(s) { c = '\0'; }

char c;
pattern(char c): c(c) { s = ""; }

pattern() { c = '\0'; s = ""; }
};

class Solution
{
public:
bool isMatch(string s, string p)
{
// get patterns
vector<pattern> patterns;
int start = 0, end = 0;
for (int i = 0; i < p.length(); i++)
{
if (p[i] == '.')
{
end = i - 1;

if (end >= start)
patterns.push_back(pattern(p.substr(start, end - start + 1)));

if (i+1 < p.length() && p[i+1] == '*')
{
patterns.push_back(pattern('.'));

i++;
}
else
patterns.push_back(pattern("."));

start = i + 1;
}
else if (p[i] == '*')
{
end = i - 2;

if (end >= start)
patterns.push_back(pattern(p.substr(start, end - start + 1)));

patterns.push_back(pattern(p[i-1]));

start = i + 1;
}
}
if (p[p.length() - 1] != '*')
patterns.push_back(pattern(p.substr(start)));

// print patterns
/*
for (int i = 0; i < patterns.size(); i++)
{
cout << "Patterns[" << i << "]: ";
if (patterns[i].s.length() > 0)
cout << patterns[i].s << " ";
else
cout << patterns[i].c << "* ";
cout << endl;
}
*/

int patternIndex = 0;
int m = 0;
stack<backtrackPoint> backtrackPoints;
bool backtrack = false;
while (true)
{
//cout << "stringIndex: " << m << " patternIndex: " << patternIndex << " backtrackPoints.size(): " << backtrackPoints.size() << endl;

if (patternIndex == patterns.size()) // pass all sub pattern(s), check
{
if (m == s.length())
return true;
if (m < s.length()) // the whole string matches preceding sub pattern(s) of the whole pattern, backtrack
{
if (backtrackPoints.size() > 0)
{
backtrackPoint point = backtrackPoints.top();
backtrackPoints.pop();
m = point.stringIndex;
patternIndex = point.patternIndex;
backtrack = true;
continue;
}
else
return false;
}
}

pattern currentPattern = patterns[patternIndex];

if (m == s.length())
{
bool flag = true;
for (int idx = patternIndex; idx < patterns.size(); idx++)
if (patterns[idx].s.length() > 0)
{
flag = false;
break;
}
if (flag) // current and latter sub pattern(s) are all star expression(s)
return true;
else // backtrack
{
if (backtrackPoints.size() > 0)
{
backtrackPoint point = backtrackPoints.top();
backtrackPoints.pop();
m = point.stringIndex;
patternIndex = point.patternIndex;
backtrack = true;
continue;
}
else
return false;
}
}

if (currentPattern.s.length() > 0) // trivial string
{
if (currentPattern.s.compare(".") == 0 || s.compare(m, currentPattern.s.length(), currentPattern.s) == 0)
{
m += currentPattern.s.length();
patternIndex++;
}
else // backtrack
{
if (backtrackPoints.size() > 0)
{
backtrackPoint point = backtrackPoints.top();
backtrackPoints.pop();
m = point.stringIndex;
patternIndex = point.patternIndex;
backtrack = true;
continue;
}
else
return false;
}
}
else // star expression
{
if (backtrack == true) // eat a character
{
backtrack = false;
if (currentPattern.c == '.' || s[m] == currentPattern.c) // eat a character
{
m++;
backtrackPoints.push(backtrackPoint(m, patternIndex));
patternIndex++;
}
else // backtrack
{
if (backtrackPoints.size() > 0)
{
backtrackPoint point = backtrackPoints.top();
backtrackPoints.pop();
m = point.stringIndex;
patternIndex = point.patternIndex;
backtrack = true;
continue;
}
else
return false;
}
}
else // eat no character, i.e. pass current star expression
{
backtrackPoints.push(backtrackPoint(m, patternIndex));
patternIndex++;
}
}
}
cout << "Error: undefined!" << endl;
}
};
Runtime: 368 ms



Recursive Code

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*
return isMatch(s, p.substr(2)) ||
!s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p);
else
// trivial string
return !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p.substr(1));
}
};
Runtime: 624 ms

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: