剑指offer:正则表达式匹配
剑指offer:正则表达式匹配
题意描述
请实现一个函数用来匹配包括'.'和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
解题思路
一、思路一
- 两个字符串都为空,返回true
- 当第一个字符串不空,而第二个字符串空了,返回false(因为这样,就无法匹配成功了,而如果第一个字符串空了,第二个字符串非空,还是可能匹配成功的,比如第二个字符串是“aaaa”,由于‘ * ’之前的元素可以出现0次,所以有可能匹配成功)
- 开始匹配第一个字符,这里有两种可能:匹配成功或匹配失败。但考虑到pattern下一个字符可能是‘ * ’, 这里我们分两种情况讨论:pattern下一个字符为‘ * ’或不为‘ * ’:
- pattern下一个字符不为‘ * ’:
- 如果str第一个字符和ptr中的第一个字符相匹配,那么str和ptr都后移一个字符,然后匹配剩余的。
- 如果str第一个字符和ptr中的第一个字符相不匹配,直接返回false。
- pattern下一个字符为‘ * ’时,稍微复杂一些,因为‘ * ’可以代表0个或多个。这里把这些情况都考虑到:
- x* 匹配0个字符,str不变,ptr后移两位,跳过这个’ * ‘
- x* 匹配1个字符时,str+1,ptr+2,匹配str下个字符,并且跳过’ * ‘
- x* 匹配多个字符时,str+1,ptr不变,继续匹配str下个字符
- 匹配一个也可以看成匹配多个
- pattern下一个字符不为‘ * ’:
public class Solution {
public boolean match(char[] str, char[] pattern){
if(str == null && pattern == null) return true; //str、pattern都为空,返回true
if(str != null && pattern == null) return false;//str不为空,pattern为空,匹配失败
return matchCore(str,0,pattern,0);
}
public boolean matchCore(char[] str, int s1, char[] ptr, int p1) {
//str匹配到尾部,ptr匹配到尾部,匹配成功
if(s1 == str.length && p1 == ptr.length){
return true;
}
//str没有匹配到尾部,ptr匹配到尾部,匹配失败
if(s1 != str.length && p1 == ptr.length){
return false;
}
//p1的下一个字符为‘*’,并且没有越界
if(p1+1<ptr.length && ptr[p1 + 1] == '*'){
//如果s1没有匹配到尾部,p1 == s1 或者p1 = ‘。’
if((s1 != str.length && ptr[p1] == str[s1]) ||(ptr[p1] == '.' && s1 != str.length)){
return matchCore(str,s1,ptr,p1+2) || //X*匹配0个字符
//matchCore(str,s1+1,ptr,p1+2)|| //X*匹配1个字符
matchCore(str,s1+1,ptr,p1); //X*匹配多个字符,继续匹配s1下个字符
}else{
//s1 != p1 并且 p1 != ‘。’,匹配不成功,跳过‘ * ’
return matchCore(str,s1,ptr,p1 + 2);
}
}
//str没有匹配到尾部,p1 == s1 或者 p1 = ‘。’,但p1下一位不是‘*’
if((s1 != str.length && ptr[p1] == str[s1])||(ptr[p1] == '.' && s1 != str.length)){
//匹配s1下一位与p1下一位
return matchCore(str,s1 + 1,ptr,p1 + 1);
}
return false;
}
}
二、思路二
- 使用动态规划,DP分为正向与反向,这里使用那种呢?
- 根据前面
matchCore(str,s1 + 1,ptr,p1 + 1),相当于dp[ i ] [ j ] = dp[ i + 1 ] [ j + 1 ],所以我么采用反向 - 初始化
boolean dp[ len1 + 1 ] [ len2 + 1 ],其中len1=str.length,len2=pattern.length - 初始化
dp[ len1 ] [ len2 ] = true,含义是从两个字符串的末位开始匹配,“”与“”一定为true - 循环
- 外循环:因为我们要用aa*匹配aaa,以aaa为外循环,注意,从""开始匹配接下来a,aa,aaa
- 内循环:拿aa* 匹配:匹配顺序 * ,a* ,aa*
public class Solution {
public boolean match(char[] str, char[] pattern){
if(str == null || pattern == null) return true;
boolean[][] dp = new boolean[str.length+1][pattern.length+1];
dp[str.length][pattern.length] = true; //末尾“”与“”一定匹配
for(int i=str.length;i>=0;i--){ //从空串开始匹配
for(int j=pattern.length-1;j>=0;j--){//从最后一个字符开始匹配
if(j+1<pattern.length && pattern[j+1] == '*'){ //下一位是*,并且没有越界
//str = ptr 或者 ptr+1 = 。
if(i < str.length && (str[i] == pattern[j] || pattern[j] == '.')){
dp[i][j] = dp[i][j+2] || dp[i + 1][j]; //匹配0个、1个或多个
}else{
dp[i][j] = dp[i][j+2]; //跳过*
}
}else{
//下一位不是*,并且str = ptr || ptr+1 = 。
if(i != str.length &&(str[i] == pattern[j] || pattern[j] == '.')){
dp[i][j] = dp[i+1][j+1]; //匹配下一位
}
}
}
}
return dp[0][0];
}
}

浙公网安备 33010602011771号