1 题目描述
2 算法思路
题目中的重点
- 式中的字符
'.'
表示任意一个字符- 而
'*'
表示它前面的字符可以出现任意次(含0次) 例如: a*b 可以视作 aaaaaaaaaaab
需要注意的是 .* 这种情况,可以认为这里的 '*' ,可以换做n个 '.'
输入: s = "ab" p = ".*" 输出: true 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
思路:动态规划
首先定义状态:
dp[i][j] :s前 i 个字符是否能够和p的前 j 个字符匹配上。
当我们已知 dp[i - 1][j - 1]时,可能存在三种情况,
- p[ j - 1] == s[ i - 1]
- p[ j - 1] 为字符 '*'
- p[ j - 1] 为字符 '.'
- 完整思路
s[i-1]==p[j-1] 此时字符相等,直接dp[i][j] = dp[i-1][j-1];
s[i-1]!=p[j-1],此时字符不等,分为三种情况
- p[ j - 1] != s[ i - 1] 直接dp[i][j] = false;
- p[ j - 1] 为字符 '*' :这种情况最复杂,下面单独讨论
- p[ j - 1] 为字符 '.' 由于 ’.’等于任何字符,因此直接dp[i][j] = dp[i-1][j-1];
p[ j - 1] 为字符 '*'
- p[j-2]!=s[i-1] :p的前一位不等于s,那就只能让*代表取0个字符,则 dp[i][j] = dp[i][j-2]
p[j-2]==s[i-1] || p[j-2]=='.'
'*' 看作0个字符的情况,例如s = aab p = aabb* 此时已经匹配成功了,表示前面的一个b出现0次
'*'看作一个字符,例如s = aab p = aab*,因此b* 就看作出现了一次b
'*' 看作多个字符,例如s = aabb , p = aab*,b*就需要看成两个b
初始化:
- dp[0][0] = true;
- 本题还必须初始第一行,dp[0][j]
3 代码
class Solution {
public boolean isMatch(String s, String p) {
//需要分别取出s和p为空的情况,所以dp数组大小+1
boolean[][] dp=new boolean[s.length()+1][p.length()+1];
//初始化dp[0][0]=true,dp[0][1]和dp[1][0]~dp[s.length][0]默认值为false所以不需要显式初始化
dp[0][0]=true;
//填写第一行dp[0][2]~dp[0][p.length]
for (int k=2;k<=p.length();k++){
//p字符串的第2个字符是否等于'*',此时j元素需要0个,所以s不变p减除两个字符
dp[0][k]=p.charAt(k-1)=='*'&&dp[0][k-2];
}
//填写dp数组剩余部分
for (int i=0;i<s.length();i++){
for (int j=0;j<p.length();j++){
//p第j个字符是否为*
if (p.charAt(j)=='*'){
//两种情况:1.s不变[i+1],p移除两个元素[j+1-2]。
// 2.比较s的i元素和p的j-1(因为此时j元素为*)元素,相等则移除首元素[i+1-1],p不变。
dp[i+1][j+1]=dp[i+1][j-1]||
(dp[i][j+1]&&headMatched(s,p,i,j-1));
}else {
//s的i元素和p的j元素是否相等,相等则移除s的i元素[i+1-1]和p的j元素[j+1-1]
dp[i+1][j+1]=dp[i][j]&&headMatched(s,p,i,j);
}
}
}
return dp[s.length()][p.length()];
}
//判断s第i个字符和p第j个字符是否匹配
public boolean headMatched(String s,String p,int i,int j){
return s.charAt(i)==p.charAt(j)||p.charAt(j)=='.';
}
}
4 提交结果