LeeCode (dynamic rules, greedy algorithm) 44_ wildcard matching
Topic:
Given a string(s) and a character pattern§, implement a wildcard matching that supports'?' and'*'.
'?' can match any single character.
'*' can match any string (including empty strings).
Only when two strings match exactly is the match successful.
Description:
s may be empty and only contain lowercase letters from az.
p may be empty and only contain lowercase letters from az, as well as the characters? and *.
Example 1:
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" cannot match the entire string of "aa".
Example 2:
Input:
s = "aa"
p = " "
Output: true
Explanation: ' ' can match any string.
Example 3:
Input:
s = “cb”
p = “?a”
Output: false
Explanation:'?' can match'c', but the second'a' cannot match'b'.
Example 4:
Input:
s = "adceb"
p = " a b"
Output: true
Explanation: The first ' ' can match the empty string, and the second ' ' can match the string "dce".
Example 5:
Input:
s = “acdcb”
p = “a*c?b”
Output: false
Source: LeetCode
Link: https://leetcode-cn.com/problems/wildcard-matching
Copyright is owned by LeetCode . For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Problem-solving ideas:
Method one:
dynamic programming
- Create a dp[][] to save all matching conditions, and use dp[i][j] to indicate whether the first i characters of s and the first j characters of p match.
- The matching situation is roughly divided into three types:
1. si=pi
2. pi is the number
3. pi is the * number
The state transition equation after integration:
Determine the boundary:
-
dp[0][0]=True, that is, when the string s and the pattern p are both empty, the match is successful;
-
dp[i][0]=False, that is, an empty pattern cannot match a non-empty string;
-
dp[0][j] needs to be discussed separately: because the asterisk can match the empty string, dp[0][j] is true only when the first j characters of the pattern p are all asterisks.
Java code:
public class 通配符匹配 {
public boolean isMatch(String s,String p){
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m+1][n+1];
dp[0][0] =true;
for(int i=1;i<=n;i++){
if(p.charAt(i-1)=='*'){
dp[0][i]=true;
}else{
break;
}
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(p.charAt(j-1)=='*'){
dp[i][j]=dp[i-1][j] || dp[i][j-1];
}else if(p.charAt(j-1)=='?' || p.charAt(j-1)==s.charAt(i-1)){
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
}
Method 2:
Greedy Algorithm
-
Because it can match one or more characters, all n and 1 * are actually equivalent. So we can regard p as p=∗ u1∗u2∗u3∗u4∗u5∗u6∗
-
The essence of the algorithm is to first find u1 in s and then find u2, u3...
In addition, there are two situations:
- The beginning character of pattern p is not an asterisk;
- The ending character of pattern p is not an asterisk.
The second case is not complicated to deal with. If the end character of the pattern p is not an asterisk, then it must match the end character of the string s. Then we keep matching the ending characters of s and p until p is empty or the ending character of p is an asterisk. In this process, if the match fails, or finally p is empty but s is not empty, then False needs to be returned.
The handling of the first case is similar, we can continuously match the beginning characters of s and p. Another processing method is given in the following code, which is to modify the initial value of sRecord and tRecord to −1, which means that the beginning character of the pattern p is not an asterisk, and it is judged when the match fails, if their value is still − 1. It means that there is no chance to "return" the match again.
Java code:
public class 通配符匹配 {
public boolean isMatch(String s, String p) {
int sRight = s.length();
int pRight = p.length();
//不是以*号结尾
while(sRight>0 && pRight>0 && p.charAt(pRight-1)!='*'){
if(charMatch(s.charAt(sRight-1),p.charAt(pRight-1))){
--sRight;
--pRight;
}else{
return false;
}
}
if(pRight==0){
return sRight==0;
}
int sIndex=0,pIndex=0;
int sRecord=-1,pRecord=-1;
while(sIndex<sRight && pIndex<pRight){
if(p.charAt(pIndex)=='*'){
++pIndex;
sRecord=sIndex;
pRecord=pIndex;
}else if(charMatch(s.charAt(sIndex),p.charAt(pIndex))){
++pIndex;
++sIndex;
}else if(sRecord!=-1 && sRecord+1 < sRight){
++sRecord;
sIndex = sRecord;
pIndex = pRecord;
}else{
return false;
}
}
return allStars(p,pIndex,pRight);
}
public boolean allStars(String str, int left, int right) {
for(int i=left;i<right;i++){
if(str.charAt(i)!='*'){
return false;
}
}
return true;
}
public boolean charMatch(char u, char v) {
return u==v || u=='?';
}
}