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 = “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
这道题中的* 表示之前那个字符可以有0个,1个或是多个,就是说,字符串a *b,可以表示b或是aaab,即a的个数任意,这道题分的情况的要复杂一些,需要用递归Recursion来解,大概思路如下:
-
若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=“a*b”,直接进入while循环后,我们发现"ab"和"b"不匹配,所以s变成"b",那么此时跳出循环后,就到最后的return来比较"b"和"b"了,返回true。再举个例子,比如s="", p=“a *”(a和 *之间没有空格),由于s为空,不会进入任何的if和while,只能到最后的return来比较了,返回true,正确)。
#include<iostream>
using namespace std;
class Solution {
public:
bool isMatch(string s, string p) {
if(p.empty()) return s.empty();
if(p.size()==1) return (s.size()==1 && (s[0]==p[0] || p[0]=='.'));
/*
//其实上面这句也可以这么写
if(p.size()==1)
if(s.size()==1 && (s[0]==p[0] || p[0]=='.'))
return true;
else
return false;
//但上面不能这么写,下面是错误写法。
if(p.size()==1 && s.size()==1 && (s[0]==p[0] || p[0]=='.'))
return true;
else
return false;
//仔细体会两种写法的区别,别搞错了。错误写法的错误之处在于当p.size()不为1时就会返回false,这样显然有问题
*/
if(p[1] != '*'){
if(s.empty()) return false;
return ((s[0]==p[0] || p[0]=='.') && isMatch(s.substr(1),p.substr(1)));
//当s和p的长度大于1且p的第二个不是*时,要一个一个地比较s和p的元素,并每次都去掉开头第一个位置的元素
}
while(!s.empty() && (s[0]==p[0] || p[0]=='.')){
if(isMatch(s,p.substr(2))) return true; //这样做的原因是假设此时的星号的作用是让前面的字符出现0次,验证是否匹配
s=s.substr(1); //因为此时首字母匹配了,我们可以去掉s的首字母,而p由于星号的作用,可以有任意个首字母,所以不需要去掉
}
return isMatch(s,p.substr(2));
//上面这个return,也就是最后一个return作用是:
//这么做的原因是处理星号无法匹配的内容,比如s="ab", p="a*b",直接进入while循环后,我们发现"ab"和"b"不匹配,所以s变成"b",那么此时跳出循环后,就到最后的return来比较"b"和"b"了,返回true。
//再举个例子,比如s="", p="a*",由于s为空,不会进入任何的if和while,只能到最后的return来比较了,返回true,正确
}
};
int main(){
Solution S;
cout << S.isMatch("ab","a*b");
return 0;
}
参考网址:
http://www.cnblogs.com/grandyang/p/4461713.html
https://leetcode.com/problems/regular-expression-matching/