Leetcode 10 Regular Expression Matching
leetcode 10 Regular Expression Matching
简介
此题让实现一个简单的正则表达式。
该表达式只需要有如下功能
- a 匹配字符 'a'
- a* 匹配零或多个 a
- .匹配任意字符
- .* 匹配零或多个任意字符
思路
把正则式分解,
- 单字符通配为一类,如'a','b','.'
- 若干通配为一类,如 'a','.'
当拿到一个 待匹配字符 varChar 和一个正则字符 reg 后,
如果当前正则字符是单字符通配
- 若二者匹配,继续匹配下一个字符和下一个正则字符
- 若二者不匹配,即返回不匹配
如果当前正则字符是若干通配 - 若二者匹配,可能有以下几种情况
- 下一个字符与下一个正则字符匹配
- 下一个字符与当前正则字符匹配
- 若二者不匹配,有两种可能
- 不匹配
- 当前若干通配符匹配0个字符,继续匹配当前字符和下一个正则符
终止时,
- 如果正则串到尾部,而待匹配串未到尾部说明匹配失败
- 如果待匹配串到尾部,而正则串未到尾部,则
- 如果正则串后面(匹配0个)都是若干通配符匹配成功
- 如果后面有单字符通配符则匹配失败
- 如果正则串和待匹配串都到尾部说明匹配成功
实现
AC的代码是用递归实现的。效率很差,需要运行1000ms。
#include <string>
#include <vector>
#include <iostream>
using namespace std;
// . -> char
// .* -> n*char
// x -> x
// x* -> x * n
class Solution
{
private:
vector<string> parsedPattern;
string base;
public:
bool isMatch ( string s, string p )
{
//fafafaxydeadasfxydtsdaxy
//.*xy.t.*xy
base = s;
parsedPattern = parsePattern ( p );
return recursionMatch ( 0, 0 );
}
bool recursionMatch ( int posStr, int posVec )
{
//string a = "bbbba";
//string p = ".*a*a";
if ( posStr >= base.size() && posVec >= parsedPattern.size() ) return true;
if ( posStr >= base.size() && posVec < parsedPattern.size() )
{
return allIsStar ( posVec );
}
if ( posStr < base.size() && posVec >= parsedPattern.size() ) return false;
string& pattern = parsedPattern[posVec];
if ( hasStar ( pattern ) )
{
return match ( base[posStr], parsedPattern[posVec] ) && (
( recursionMatch ( posStr + 1, posVec + 1 ) )
|| ( recursionMatch ( posStr + 1, posVec ) )
)
||
recursionMatch ( posStr, posVec + 1 ) ;
}
else
{
return match ( base[posStr], parsedPattern[posVec] ) && ( recursionMatch ( posStr + 1, posVec + 1 ) );
}
}
bool allIsStar ( int pos )
{
bool isStar = true;
for ( int i = pos; i < parsedPattern.size(); i++ )
{
isStar &= hasStar ( parsedPattern[i] );
}
return isStar;
}
static bool match ( char source, const string& pattern )
{
return pattern[0] == '.' || pattern[0] == source;
}
static bool hasStar ( const string& value )
{
return value.size() == 2 && value[1] == '*';
}
static vector<string> parsePattern ( const string& p )
{
vector<string> parsed;
int i = 0;
while ( i < p.size() )
{
if ( i + 1 < p.size() )
{
if ( p[i + 1] == '*' )
{
parsed.emplace_back ( move ( string{ p[i], p[i + 1] } ) );
i = i + 2;
}
else
{
parsed.emplace_back ( move ( string{ p[i]} ) );
i++;
}
}
else
{
parsed.emplace_back ( move ( string{ p[i] } ) );
i++;
}
}
return parsed;
}
};
int main()
{
string a = "fafafaxydeadasfxydtsdaxy";
string p = ".*xy.t.*xy.*";
cout << Solution().isMatch ( a, p ) << "\n";
system ( "pause" );
}
改善
运用动态规划的思想,添加一个变量int dp[256][256];
用于存储recursionMatch ( int posStr, int posVec )的状态
可以避免很多次重复计算。时间也从1000ms进步到49ms。
如下
#include <string>
#include <vector>
#include <iostream>
using namespace std;
// . -> char
// .* -> n*char
// x -> x
// x* -> x * n
class Solution
{
private:
vector<string> parsedPattern;
string base;
int dp[256][256];
public:
bool isMatch ( string s, string p )
{
//fafafaxydeadasfxydtsdaxy
//.*xy.t.*xy
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < 256; j++)
{
dp[i][j] = -1;
}
}
base = s;
parsedPattern = parsePattern ( p );
return recursionMatch ( 0, 0 );
}
bool recursionMatch ( int posStr, int posVec )
{
if (dp[posStr][posVec] != -1)
{
return dp[posStr][posVec];
}
bool ans = false;
//string a = "bbbba";
//string p = ".*a*a";
if ( posStr >= base.size() && posVec >= parsedPattern.size() ) return true;
if ( posStr >= base.size() && posVec < parsedPattern.size() )
{
ans = allIsStar ( posVec );
dp[posStr][posVec] = ans ? 1 : 0;
return ans;
}
if ( posStr < base.size() && posVec >= parsedPattern.size() ) return false;
string& pattern = parsedPattern[posVec];
if ( hasStar ( pattern ) )
{
ans = match(base[posStr], parsedPattern[posVec]) && (
( recursionMatch ( posStr + 1, posVec + 1 ) )
|| ( recursionMatch ( posStr + 1, posVec ) )
)
||
recursionMatch ( posStr, posVec + 1 ) ;
dp[posStr][posVec] = ans ? 1 : 0;
return ans;
}
else
{
ans = match(base[posStr], parsedPattern[posVec]) && (recursionMatch(posStr + 1, posVec + 1));
dp[posStr][posVec] = ans ? 1 : 0;
return ans;
}
}
bool allIsStar ( int pos )
{
bool isStar = true;
for ( int i = pos; i < parsedPattern.size(); i++ )
{
isStar &= hasStar ( parsedPattern[i] );
}
return isStar;
}
static bool match ( char source, const string& pattern )
{
return pattern[0] == '.' || pattern[0] == source;
}
static bool hasStar ( const string& value )
{
return value.size() == 2 && value[1] == '*';
}
static vector<string> parsePattern ( const string& p )
{
vector<string> parsed;
int i = 0;
while ( i < p.size() )
{
if ( i + 1 < p.size() )
{
if ( p[i + 1] == '*' )
{
parsed.emplace_back ( move ( string{ p[i], p[i + 1] } ) );
i = i + 2;
}
else
{
parsed.emplace_back ( move ( string{ p[i]} ) );
i++;
}
}
else
{
parsed.emplace_back ( move ( string{ p[i] } ) );
i++;
}
}
return parsed;
}
};
int main()
{
string a = "fafafaxydeadasfxydtsdaxy";
string p = ".*xy.t.*xy.*";
cout << Solution().isMatch ( a, p ) << "\n";
system ( "pause" );
}