示例1:
输入:" aaa ", " a*a "
返回值:true
示例2:
输入:
输入:"aad","c*a*d"
返回值:true
说明:因为这里 c 为 0 个,a被重复一次, * 表示零个或多个a。因此可以匹配字符串 "aad"。
示例3:
输入:"",".*"
返回值:true
说明:".*" 表示可匹配零个或多个('*')任意字符('.')
思路及解答:
递归解答:原串定义为str,模式串为pattern。
1、如果pattern长度为0
2、如果pattern的长度大于0
3、如果pattern的长度大于1,且第二个字符是*,说明前面的字符可以匹配0,1或者多次。分为两种情况:
注意:上面说的第一个字符是不是匹配,除了两个字符相等的情况,其实还有模式串的字符为'.'的情况。
Java实现代码如下:
public boolean match(String str,String pattern){
if(pattern.length() == 0){
return str.length() == 0;
}
//第二个字符是' * '
if(pattern.length() > 1 && pattern.charAt(1) == ' * '){
//匹配0次,直接把' * '去掉,两者判断
return match(str , pattern.substring(2))
//第一个字符相同的时候,去掉第一个字符,判断后面的(相当于匹配多次)
||(str.length() > 0 && firstSame(str,pattern)) && match(str.substring(1),pattern);
//
}else{
//第二个字符不是' * '的时候,判断第一个字符是否相同,相同的时候再从第二位开始比较
return str.length() > 0 && firstSame(str,pattern) && (match(str.substring(1),pattern.substring(1)));
}
}
//判断第一个字符是不是相同
private boolean firstSame(String s, String p){
//两个相同,或者有一个是“ . ”
return s.charAt(0) == p.charAt(0) || p.charAt(0) == '.';
}
动态规划解法:
1、首先需要定义状态,用一个二维表dp[i][j]用来表示str的前i个字符和pattern的前j个字符是否匹配。
2、需要初始化简单状态,因为后面的状态是依赖于前面的状态,因此需要初始化dp[i][j]的首行和首列。
dp[0][0] = true,表示两个空的字符串是匹配的。
dp的首列,除了dp[0][0]为true,其他都是false。因为pattern为空,但是s不为空的时候,肯定不匹配。
dp数组的首行,也就是str为空的时候,如果pattern的偶数位都是“ * ”,那么就可以匹配,因为可以选择匹配0次。
3、初始化前面之后,后面的从索引1开始匹配
如果dp[i- 1][j] = true且pattern[j-2] == ' . '的时候,则dp[i][j] = true。(表示str的前i-1个字符和pattern的前j个字符匹配,并且pattern的第j-1个是' . ',第j个是' * ',那么说明可以匹配任何字符任何次数,自然str可以多匹配一个字符。)
如果dp[i- 1][j] = true且str[i-1] == pattern[j-2],则dp[i][j] = true。(如果str的前i-1个字符和pattern的前j个字符匹配,并且str的第i个字符和pattern的第j-1个字符相等,相当于' * '前面的字符出现了1次。
如果dp[i-1][j] = true且pattern[j-2] == ' . '的时候,则dp[i][j] = true。(表示str的前 i - 1个字符和pattern的前j个字符匹配,并且pattern的前j个字符匹配,并且pattern的第j-1个字符是' . ',第j个是' * ',那么说明可以匹配任何字符任何次数,自然str可以多匹配一个字符。)
如果dp[i-1][j-1] = true and str[i-1] == pattern[j-1] 时,则dp[i][j] = true(也就是前面匹配,接下来的字符一样匹配 )
如果dp[i-1][j-1] = true 且 pattern[i-1] == '.' 时,则dp[i][j] = true(其实就是 . 可以匹配任何字符)
处理完数组之后,最后返回dp[n-1][m-1]
,也就是str
的前n
个和pattern
的前m
个字符是否匹配。
Java代码实现如下:
public boolean match(String str, String pattern){
if(pattern.length() == 0){
return str.length() == 0;
}
int n = str.length() + 1;
int m = pattern.length() + 1;
boolean[][] dp = new boolean[n][m];
dp[0][0] = true;
for(int j = 2; j < m; j = j + 2){
if(dp[0][j - 2] && pattern.charAt(j - 1) == '*'){
dp[0][j] = true;
}
}
for(int i = 1 ; i < n ; i++){
for(int j = 1 ; j < m ; j++){
if(pattern.charAt(j - 1) == '*'){
dp[i][j] = dp[i][j - 2]
|| dp[i - 1][j] && (str.charAt(i -1) == pattern.charAt(j - 2)
|| pattern.charAt(j - 2) == '.');
}else{
dp[i][j] = dp[i - 1][j - 1] && (str.charAt(i -1) == pattern.charAt(j -1)
|| pattern.charAt(j - 1) == '.');
}
}
}
return dp[n - 1][m - 1];
}
时间复杂度 O(mn)
: 其中 m
,n
分别为 str
和 pattern
的长度,状态转移需遍历整个 dp
矩阵。 空间复杂度 O(mn)
: 状态矩阵 dp
使用 O(mn)
的额外空间。