Regular Expression Matching
Given an input string (s) and a pattern §, 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).
Note:
s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like . or *.
Example 1:
Input:
s = “aa”
p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.
Example 2:
Input:
s = “aa”
p = “a*”
Output: true
Explanation: ‘*’ means zero or more of the precedeng element, ‘a’. Therefore, by repeating ‘a’ once, it becomes “aa”.
Example 3:
Input:
s = “ab”
p = “."
Output: true
Explanation: ".” means “zero or more (*) of any character (.)”.
Example 4:
Input:
s = “aab”
p = “cab”
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches “aab”.
Example 5:
Input:
s = “mississippi”
p = “misisp*.”
Output: false
解析
字符串匹配,‘.’可以匹配任何字符,‘*’前面必须有字符,可以为前面字符的0个或者多个。
解法1:递归
-
若p为空,若s也为空,返回true,反之返回false。
-
若p的长度为1,若s长度也为1,且相同或是p为’.'则返回true,反之返回false。
-
若p的第二个字符不为*,若此时s为空返回false,否则判断首字符是否匹配,且从各自的第二个字符开始调用递归函数匹配。
-
若p的第二个字符为*,进行下列循环,条件是若s不为空且首字符匹配(包括p[0]为点),调用递归函数匹配s和去掉前两个字符的p(这样做的原因是假设此时的星号的作用是让前面的字符出现0次,验证是否匹配),若匹配返回true,否则s去掉首字母(因为此时首字母匹配了,我们可以去掉s的首字母,而p由于星号的作用,可以有任意个首字母,所以不需要去掉),继续进行循环。
-
返回调用递归函数匹配s和去掉前两个字符的p的结果(这么做的原因是处理星号无法匹配的内容,比如s=“ab”, p=“ab",直接进入while循环后,我们发现"ab"和"b"不匹配,所以s变成"b",那么此时跳出循环后,就到最后的return来比较"b"和"b"了,返回true。再举个例子,比如s="", p="a”,由于s为空,不会进入任何的if和while,只能到最后的return来比较了,返回true,正确)。
简洁来说就是
当p为空,返回s是否为空;
当p大于1时并且第二个为’*'时,分为两种,一种是星号表示为前面0个,一种是s不为空,并且s和p的第一个匹配时,p往后移两位
否则,一个一个匹配。
class Solution {
public:
bool isMatch(string s, string p) {
int len1 = s.size();
int len2 = p.size();
if(len2==0)
return len1==0;
if(len2>1 && p[1]=='*')
return isMatch(s,p.substr(2)) ||
(len1 && (s[0]==p[0] || p[0]=='.') && isMatch(s.substr(1),p));
else
return (len1 && (s[0]==p[0] || p[0]=='.') && isMatch(s.substr(1),p.substr(1)));
}
};
解法2:动态规划
用一个二维数组dp[i][j]表示s的前i个字符和p的前j个字符匹配。
- dp[i][j] = dp[i-1][j-1]: s[i]==p[j] || p[j]=’.’
- 当p[j]==’*"时,分为两种情况:
s[i] != p[j-1],此星号表示为空,dp[i][j] = dp[i][j-2]
s[i] = p[j-1],dp[i][j] = dp[i][j-2] 星号表示重复0次
dp[i][j] = dp[i][j-1] 星号表示重复1次
dp[i][j] = dp[i-1][j] 星号表示重复多次
初始化dp,
dp[0][0]=true;
第0列,初始化为false,
for (int i = 1; i <= m; i++)
dp[i][0] = false;
第0行,只有X能匹配空串,如果有,它的真值一定和dp[0][j-2]的相同(略过它之前的符号)
for (int j = 1; j <= n; j++)
dp[0][j] = j > 1 && ‘*’ == p[j - 1] && dp[0][j - 2];
class Solution {
public:
bool isMatch(string s, string p) {
int len1 = s.size();
int len2 = p.size();
vector<vector<bool> > dp(len1+1, vector<bool>(len2+1,false));
dp[0][0]=1;
for(int i=1;i<=len1;i++)
dp[i][0] = false;
for(int j=1;j<=len2;j++)
dp[0][j] = j>1 && '*' == p[j-1] && dp[0][j-2];
for(int i=1;i<=len1;i++){
for(int j=1; j<=len2;j++){
if(p[j-1]=='*')
dp[i][j] = dp[i][j-2] || (s[i-1] == p[j-2] || p[j-2] == '.') && dp[i-1][j];
else
dp[i][j] = (p[j-1] == '.' || s[i-1] == p[j-1]) && dp[i-1][j-1];
}
}
return dp[len1][len2];
}
};
参考
https://hk029.gitbooks.io/leetbook/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/010.%20Regular%20Expression%20Matching/010.%20Regular%20Expression%20Matching.html
http://www.cnblogs.com/grandyang/p/4461713.html

本文介绍了一种实现正则表达式匹配的方法,支持‘.’和‘*’两个特殊字符,详细解析了递归和动态规划两种解题思路,并提供了代码示例。
325

被折叠的 条评论
为什么被折叠?



