题目地址:
https://www.lintcode.com/problem/wildcard-matching/description
给定一个字符串
s
s
s和一个模式串
p
p
p,
p
p
p中含字母,'?'
或者'*'
。其中'?'
可以匹配任何单个字符,'*'
可以匹配任意字符串,包括空串。问
s
s
s是否符合
p
p
p所代表的模式。
该题的思考方式与Regular Expression Matching这个问题非常相似,可以参考https://blog.csdn.net/qq_46105170/article/details/109213897。下面详细说明。
思路是动态规划。设
f
[
i
]
[
j
]
f[i][j]
f[i][j]是
s
s
s的前
i
i
i个字符和
p
p
p的前
j
j
j个字符是否匹配(
i
i
i和
j
j
j从
1
1
1开始计数),即
s
[
0
:
i
−
1
]
s[0:i-1]
s[0:i−1]是否和
p
[
0
:
j
−
1
]
p[0:j-1]
p[0:j−1]匹配。那么可以按照
p
[
j
−
1
]
p[j-1]
p[j−1]的匹配方式来分类:
1、如果
p
[
j
−
1
]
p[j-1]
p[j−1]不是'*'
,那必然有
s
[
0
:
i
−
1
]
s[0:i-1]
s[0:i−1]非空,并且要么
s
[
i
−
1
]
=
p
[
j
−
1
]
s[i-1]=p[j-1]
s[i−1]=p[j−1],
p
[
j
−
1
]
p[j-1]
p[j−1]是'?'
。这样
p
p
p最后一个字符匹配好之后,还需要
s
[
0
:
i
−
2
]
s[0:i-2]
s[0:i−2]与
p
[
0
:
j
−
2
]
p[0:j-2]
p[0:j−2]也要匹配。所以有:
f
[
i
]
[
j
]
=
(
s
[
i
−
1
]
=
p
[
j
−
1
]
∨
p
[
j
−
1
]
=
?
)
∧
f
[
i
−
1
]
[
j
−
1
]
f[i][j]=(s[i-1]=p[j-1]\lor p[j-1]=?)\land f[i-1][j-1]
f[i][j]=(s[i−1]=p[j−1]∨p[j−1]=?)∧f[i−1][j−1]2、如果
p
[
j
−
1
]
p[j-1]
p[j−1]是'*'
,那么这个'*'
有两种匹配方式,一种是匹配空串,那么能匹配当前仅当
s
[
0
:
i
−
1
]
s[0:i-1]
s[0:i−1]与
p
[
0
:
j
−
2
]
p[0:j-2]
p[0:j−2]能匹配,也就是看
f
[
i
]
[
j
−
1
]
f[i][j-1]
f[i][j−1];另一种是匹配非空串,那么将
s
[
i
−
1
]
s[i-1]
s[i−1]删掉之后需要继续和
p
[
0
:
j
−
1
]
p[0:j-1]
p[0:j−1]匹配,即需要
s
[
0
:
i
−
2
]
s[0:i-2]
s[0:i−2]和
p
[
0
:
j
−
1
]
p[0:j-1]
p[0:j−1]要匹配,也就是看
f
[
i
−
1
]
[
j
]
f[i-1][j]
f[i−1][j]。所以有:
f
[
i
]
[
j
]
=
f
[
i
]
[
j
−
1
]
∨
f
[
i
−
1
]
[
j
]
f[i][j]=f[i][j-1]\lor f[i-1][j]
f[i][j]=f[i][j−1]∨f[i−1][j]接下来考虑初始条件,首先空串可以和空模式匹配,但非空串不能喝空模式匹配,所以有
f
[
0
]
[
0
]
f[0][0]
f[0][0]是true,但当
i
>
0
i>0
i>0,则
f
[
i
]
[
0
]
f[i][0]
f[i][0]是false。而空串是否能匹配非空模式,这一点是无法看出的,需要在递推的过程中得出。代码如下:
public class Solution {
/**
* @param s: A string
* @param p: A string includes "?" and "*"
* @return: is Match?
*/
public boolean isMatch(String s, String p) {
// write your code here
boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
for (int i = 0; i <= s.length(); i++) {
for (int j = 0; j <= p.length(); j++) {
// 空串可以匹配空模式,非空串无法匹配空模式
if (i == 0 && j == 0) {
dp[i][j] = true;
} else if (j == 0) {
dp[i][j] = false;
} else {
// 如果模式串非空,考虑模式串最后一个字符是不是'*';
if (p.charAt(j - 1) != '*') {
// 如果模式串最后一位不是'*',那么匹配当且仅当s非空,并且最后一个字符可以匹配,并且之前也可以匹配
if (i > 0 && (p.charAt(j - 1) == s.charAt(i - 1) || p.charAt(j - 1) == '?')) {
dp[i][j] |= dp[i - 1][j - 1];
}
} else {
// 如果模式串最后一位是'*',那么要么将其视为空串,要么就需要s非空并且除去最后一位之后得到的子串与p匹配
dp[i][j] |= dp[i][j - 1];
if (i > 0) {
dp[i][j] |= dp[i - 1][j];
}
}
}
}
}
return dp[s.length()][p.length()];
}
}
时空复杂度 O ( l s l p ) O(l_sl_p) O(lslp)。