leetcode 44. Wildcard Matching
Implement wildcard pattern matching with support for ‘?’ and ‘*’.
‘?’ Matches any single character.
‘*’ Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char *s, const char *p)
Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
解题思路,首先先弄明白?和*在其中的含义,
- ?代表一个的意思
- *代表0个或者多个的意思
然后自己考虑的时候,需要使用到动态规划的想法,就是构建一个2D表格,进行一个递推过程。首先,明确定义,定义二维布尔矩阵dp[m][n],第一个坐标为待匹配的字符串,第二个坐标为模式串,dp[x][y]的含义是字符串前x个字符与模式串前y个字符是否匹配,若匹配则为true,否则为false.
递推核心过程如下,
如果当前需要判断dp[i+1][j+1],即字符串的下标到达i,模式串的下标到达j。此时,分为两种情况
1. p.charAt(j) == '?' || s.charAt(i) == p.charAt(j)。
含义是如果p为此处字符为?或者p此处的字符与s此处的字符相同,
则显然dp[i+1][j+1] = dp[i][j]
2. p.charAt(j) == '*'。这种情况较为复杂。分情况讨论。
A. *代表0个字符,则此时dp[i+1][j+1]=dp[i+1][j]
B. *代表1个字符,则此时dp[i+1][j+1]=dp[i][j]
C. *代表2个字符,则此时dp[i+1][j+1]=dp[i-1][j]
D. *代表3个字符,则此时dp[i+1][j+1]=dp[i-2][j]
...
因此,最后的统一结果为
dp[i+1][j+1]=dp[i+1][j] || dp[i][j] || dp[i-1][j] ||
dp[i-2][j] || ... || dp[0][j]
需要注意的是按照上述公式,可以得到
dp[i][j+1] = dp[i][j] || dp[i-1][j] || dp[i-2][j] ||
dp[i-3][j] || ... || dp[0][j]
因此dp[i+1][j+1] = dp[i+1][j] || dp[i][j+1]
3. s.charAt(i) != p.charAt(j) 不匹配
dp[i+1][j+1] = false;
需要注意的细节为
1 需要二维布尔矩阵开始全部初始化为false,然后将dp[0][0]=true,将第0行进行初始化,dp[0][j+1] = dp[0][j] && (p.charAt(j) == ‘*’),此句话的意思是如果前面匹配,当前为 *,则肯定匹配。
2 先统计下p中非*的有多少,如果比s的总字符长度还大,说明没有必要继续做下去了(不可能匹配成功)。
具体的代码实现
public class Solution {
public boolean isMatch(String s, String p) {
if(s == null || p == null) return true;
int sLen = s.length();
int pLen = p.length();
//非star数目统计
int countNotStar = 0;
for(int i = 0; i < pLen; i++){
if(p.charAt(i) != '*'){
countNotStar += 1;
}
}
//如果非star数目比s长度还大,不可能匹配
if(countNotStar > sLen) return false;
//初始化二维矩阵,全为false
boolean[][] dp = new boolean[sLen+1][pLen+1];
dp[0][0] = true;
for(int j = 0; j < pLen; j++){
//初始化第一行数据
dp[0][j+1] = dp[0][j] && (p.charAt(j) == '*');
for(int i = 0; i < sLen; i++){
//情况1
if(p.charAt(j) == '?' || p.charAt(j) == s.charAt(i)){
dp[i+1][j+1] = dp[i][j];
}
//情况2
else if(p.charAt(j) == '*'){
dp[i+1][j+1] = (dp[i][j+1] || dp[i+1][j]);
}
//not match
else{
dp[i+1][j+1] = false;
}
}
}
return dp[sLen][pLen];
}
}