题目描述
Given an input string (s) and a pattern (p), 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 = "c*a*b"
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 = "mis*is*p*."
Output: false
分析
这道题还是比较有难度的,如果情况考虑不全的话,是很难通过的。这道题最简单的思路就是递归,只是这个递归的情况很多,有多种特殊情况需要单独考虑。另外在思考前需要明确一点,*号之前必须要有一个有效元素。
首先就考虑特殊情况,当p为空时,如果s为空返回true;如果s不为空返回false。当p的长度为1时,如果s的长度不为1返回false;如果s的长度为1,并且s和p的字母匹配,或者p为‘.’,则返回true;否则返回false。
如果p的第二个元素不为*,如果s为空返回false;如果s不为空且s和p的第一个元素匹配,则递归匹配s和p的后续元素;否则返回false。
接着就需要考虑p的第二个元素为*的情况了,这个情况是比较复杂的,因为不知道一个元素会重复多少次,所以需要使用循环来判断。在进入循环前,需要判断s是否为空,如果为空直接退出循环。因为如果p的第一个元素为‘.’,那么就有可能s一直在缩小,而p在每次循环都是不变的。这是因为s和p本身是不匹配的,所以最终s会为空,但是出现不匹配的情况,因此循环条件需要加上s不为空的情况。另外还要判断s和p的第一个元素是否匹配,如果匹配就进入循环。
循环里面首先递归匹配s和p的第三个元素开始是否匹配,这个情况就相当于*不再重复其前面的一个元素。如果匹配直接返回true;否则s从后面一个元素开始,再次进入循环,相对于p之前的元素重复次数加1。
退出循环后还需要进行一次递归匹配,匹配现在的s和p的第三个元素开始是否匹配,这是因为循环中有些情况匹配不到,所以需要最后来进行处理。比如s=“ab”,p=“a*b”。退出循环后s=“b”,而p没有变。如果p不从第三个元素开始匹配,就不会匹配到。
这道题的情况比较多,需要仔细考虑,一不小心就会考虑不全或者考虑错误。
AC代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
if(p.empty())//为空
{
return s.empty();
}
if(p.length() == 1)//长度为1
{
if(s.length() == 1)
{
if(s[0] == p[0] || p[0] == '.')
{
return true;
}
return false;
}
return false;//s长度不为1则匹配不成功
}
if(p[1] != '*')//p的第二个元素不为*
{
if(s.empty())//s不能为空
{
return false;
}
if(s[0] == p[0] || p[0] == '.')//s和p的第一个元素匹配
{
return isMatch(s.substr(1), p.substr(1));//递归匹配
}
return false;//s和p的第一个元素不匹配
}
while(!s.empty() && (s[0] == p[0] || p[0] == '.'))
{
if(isMatch(s, p.substr(2)))//递归匹配,跳过*
{
return true;
}
else
{
s = s.substr(1);//相当于*前面的元素重复出现
}
}
return isMatch(s, p.substr(2));//匹配剩下的情况,跳过*,不过此时s已经变化
}
};