2019.4.20更新
刷了LeetCode一道原题,靠着回忆手撕了递归的方法,没想到在Leetcode上效率排名很低,才发现这道题可以用DP大法来解。参考我新发的博文:LeetCode(10):正则表达式匹配 Regular Expression Matching(Java)。
2019.2.19 《剑指Offer》从零单刷个人笔记整理(66题全)目录传送门
一开始做这道正则表达式题不断用判别和循环,理了一大堆逻辑还是没法满足所有特殊情况,最后才知道要用递归做。
需要注意的是,字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。比如当表达式pattern等于“.*”的时候,输入字符str可以为任意个字符(包括空“”)。具体递归思路如下:
首先设定递归的终止条件:
1.若str和pattern同时前进至最后一个字符,则说明完全匹配,返回true。
2.若pattern比str先进行到尾部,则匹配失败,返回false。(这里注意str可以先进行到尾部,比如str="",pattern={.*})
递归情况分类:
1.pattern下一个字符存在且是‘*’号,考虑两种情形:
1-1 str当前字符与pattern当前字符匹配,考虑可能是pattern当前字符出现0次或1次或多次的情况,递归分别进行0次(pattern+2)、1次(pattern+2、str+1)、多次(pattern、str+1),其中一种满足即可(逻辑或)。
1-2 str当前字符与pattern当前字符不匹配,只可能是pattern当前字符出现0次的情况,pattern跳过两个字符,pattern+2递归继续进行。
2.pattern下一个字符不是‘*’号,且当前字符匹配或当前字符为‘.’号,当作匹配成功,pattern+1,str+1递归继续进行。
3.其他情况只可能匹配失败,返回false。
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
Java实现:
/**
*
* @author ChopinXBP
* 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。
* 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。
*
*/
public class Match_51 {
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] str = {'a', 'a', 'a'};
char[] str2 = {'a', 'a', '.', 'a'};
char[] pattern1 = {'a', '.', 'a'};
char[] pattern2 = {'a', 'b', '*', 'a', 'c', '*', 'a'};
char[] pattern3 = {'a', 'b', '*', 'a'};
System.out.println(match(str, pattern1));
System.out.println(match(str, pattern2));
System.out.println(match(str2, pattern3));
char[] str4 = new char[0];
char[] pattern4 = {'.', '*'};
System.out.println(match(str4, pattern4));
}
public static boolean match(char[] str, char[] pattern)
{
if(str == null && pattern == null)return true;
if(str != null && pattern == null)return false;
int stridx = 0;
int patidx = 0;
return Solution(str, pattern, stridx, patidx);
}
public static boolean Solution(char[] str, char[] pattern, int stridx, int patidx) {
int strlen = str.length;
int patlen = pattern.length;
//递归终止条件:从头到尾匹配成功
if(stridx == strlen && patidx == patlen) {
return true;
}
//pattern先到尾部,匹配失败(可以str先到尾,例如str="",pattern={.*})
else if(stridx != strlen && patidx == patlen) {
return false;
}
//pattern下一个字符是*号
else if(patidx + 1 < patlen && pattern[patidx + 1] == '*') {
//str当前字符匹配,考虑可能是pattern当前字符出现0次或1次或多次的情况
if(stridx != strlen && (pattern[patidx] == '.' || str[stridx] == pattern[patidx])) {
return Solution(str, pattern, stridx, patidx + 2) //出现0次
|| Solution(str, pattern, stridx + 1, patidx + 2) //出现1次
|| Solution(str, pattern, stridx + 1, patidx); //出现多次
}
//str当前字符不匹配,只可能是pattern当前字符出现0次的情况
else {
return Solution(str, pattern, stridx, patidx + 2);
}
}
//pattern下一个字符不是*号,且当前字符匹配或当前字符为.号
else if(stridx != strlen && (pattern[patidx] == '.' || pattern[patidx] == str[stridx])) {
return Solution(str, pattern, stridx + 1, patidx + 1);
}
else {
return false;
}
}
}
C++实现示例:
class Solution {
public:
bool match(char* str, char* pattern)
{
if (*str == '\0' && *pattern == '\0')
return true;
if (*str != '\0' && *pattern == '\0')
return false;
//if the next character in pattern is not '*'
if (*(pattern+1) != '*')
{
if (*str == *pattern || (*str != '\0' && *pattern == '.'))
return match(str+1, pattern+1);
else
return false;
}
//if the next character is '*'
else
{
if (*str == *pattern || (*str != '\0' && *pattern == '.'))
return match(str, pattern+2) || match(str+1, pattern);
else
return match(str, pattern+2);
}
}
};
#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#