Description
Given an input string (s) and a pattern (p), 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).
Note:
- s could be empty and contains only lowercase letters a-z.
- p could be empty and contains only lowercase letters a-z, and characters like ? or *.
Example 1:
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Example 2:
Input:
s = "aa"
p = "*"
Output: true
Explanation: '*' matches any sequence.
Example 3:
Input:
s = "cb"
p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.
Example 4:
Input:
s = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".
Example 5:
Input:
s = "acdcb"
p = "a*c?b"
Output: false
问题描述
给定字符串s和p,实现支持通配符”?”和”*”的匹配
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).
匹配需要针对整个字符串,而不是部分。
问题分析
两种做法,dfs + memorization 和 贪心
解法1(dfs + memorization)
/*
dp[i][j]记录s.substring(i)和p.substring(j)是否匹配
如果只有"?", 那么很好办,一个一个匹配就可以了
加上"*", 有两种选择, "*"匹配 或者 "*" 不匹配
匹配, backTrack(s, p, i + 1, j, dp))
不匹配, backTrack(s, p, i, j + 1, dp)
*/
class Solution {
private enum Result{
TRUE,FALSE
}
public boolean isMatch(String s, String p) {
int len1 = s.length(), len2 = p.length();
Result[][]dp = new Result[len1 + 1][len2 + 1];
return backTrack(s, p, 0, 0, dp);
}
public boolean backTrack(String s, String p, int i, int j, Result[][] dp){
if(dp[i][j] != null) return dp[i][j] == Result.TRUE;
boolean res = false;
if(j == p.length()) res = (i == s.length());
else{
if(p.charAt(j) == '*'){
res = backTrack(s, p, i, j + 1, dp) || (i < s.length() && backTrack(s, p, i + 1, j, dp));
}else{
boolean firstMatch = i < s.length() && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '?');
res = firstMatch && backTrack(s, p, i + 1, j + 1, dp);
}
}
dp[i][j] = res ? Result.TRUE : Result.FALSE;
return res;
}
}
解法2(贪心)
class Solution {
public boolean isMatch(String s, String p) {
//starj记录上一个"*"的位置
//match记录与"*"匹配的i的位置(与starj不同的是,每次回溯,match自增)
int i = 0, j = 0, starj = -1, match = 0;
while(i < s.length()){
//字符相等或者p.charAt(j) == '?'
if(j < p.length() && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '?')){
i++;
j++;
//遇到'*', 记录'*'的位置,并记录starj和match
}else if(j < p.length() && p.charAt(j) == '*'){
starj = j;
j++;
match = i;
//不是上述两种情况,无法匹配,因此回溯
//注意,若出现第二个'*', 会对之前的覆盖,因为已经不需要用之前的"*"进行回溯了
}else if(starj != -1){
j = starj + 1;
match++;
i = match;
//其他情况, 直接返回false
}else{
return false;
}
}
//清除'*'
while(j < p.length() && p.charAt(j) == '*') j++;
//若p清空,说明匹配
return j == p.length();
}
}