题目:
给定一个字符串s
和一个字符规律字符串p
,请实现一个支持*
和.
的字符串匹配,判断该字符规律p
能否匹配上字符串s
。
其中:
.
可以匹配单个字符*
可以匹配任意个前面的字符
思路:
本题需要采用动态规划
来做,求出部分解,之后通过部分解得出更大范围的解。
根据提供的信息我们可以知道,"*"前面一定是有字符的,并且每个.*
都能匹配任意两个字符。
大体总共分两种情况:
- 当前匹配串中最后的字符不为
*
。那么要么匹配s
串中的字符,要么不匹配,没有其他情况:如果匹配上了,那么:dp[i][j] = dp[i - 1][j - 1]
,只需要看前面同时去掉当前位置s和p中的最后一个字符之后剩下的是否能匹配上,只要前面的都能匹配上,那么整体就能匹配上。否则就为false - 当前匹配串中最后的字符为
*
,只要*
前面的字符能和当前s
串中的字符相同,那么能分三种小情况:1.*匹配0个字符,2.匹配一个字符,3.匹配两个以上的字符。也就是:dp[i][j] = dp[i][j - 2] || dp[i - 1][j - 2] || dp[i - 1][j]
,只要有一个为true,那么该位置就可以匹配上。 - 最后还有base case,也就是特殊情况判断以下:1.如果s为空,p为空,那么一定可以匹配,返回true,也就是
dp[0][0] = true
,2.如果s不为空,p为空,一定不匹配,返回false,3.如果s为空,p不为空,那么要看p中能否有*将前面的字符删去并最后和s匹配
以下为代码+注释,代码结合注释应该更好理解一点:
public boolean isMatch(String s, String p) {
// 将字符串转换为字符数组遍历
char[] s1 = s.toCharArray();
char[] p1 = p.toCharArray();
boolean[][] dp = new boolean[s1.length + 1][p1.length + 1];
// 初始值设置为true,也就是同时为空的那种情况
dp[0][0] = true;
// base case
// 1. s1为空,p1为空,一定为true
// 2. s1不为空,p1为空,一定为false,dp数组默认为false,因此不需要改动
// 3. s1为空,p1不为空,那么只要p串中最后的*把前面的抹去,也有可能为true
// 第三种特殊情况,将匹配串p遍历一遍,生成结果
for(int i = 1; i <= p1.length; i++){
if(p1[i - 1] == '*')
dp[0][i] = dp[0][i - 2];
}
for(int i = 1; i <= s1.length; i++){
for(int j = 1; j <= p1.length; j++){
// 情况一:p1此位置不为*,并且值和s串中能匹配上
if(s1[i - 1] == p1[j - 1] || p1[j - 1] == '.'){
// 那么当前位置的值就等于同时去掉该字符的情况的值
dp[i][j] = dp[i - 1][j - 1];
// 情况二,p1此位置为*,就要分情况讨论,匹配0个,匹配一个,或者匹配两个以上三种情况
}else if(p1[j - 1] == '*'){
// 如果*前面的值和当前s中的字符匹配
if(s1[i - 1] == p1[j - 2] || p1[j - 2] == '.'){
dp[i][j] = dp[i][j - 2] || dp[i - 1][j - 2] || dp[i - 1][j];
}else{
// 如果不匹配,那么直接查看前面不带不匹配字符的剩余字符串
dp[i][j] = dp[i][j - 2];
}
}
}
}
// 字符串遍历完,返回最后的结果
return dp[s1.length][p1.length];
}
笔者也在不断学习中,如有错误,欢迎指正!