LeeCode(動態規則,貪心演算法)44_萬用字元匹配
技術標籤:leetcode演算法javaleetcode動態規劃貪心演算法
LeeCode(動態規則,貪心演算法)44_萬用字元匹配
題目:
給定一個字串 (s) 和一個字元模式 § ,實現一個支援 ‘?’ 和 ‘*’ 的萬用字元匹配。
‘?’ 可以匹配任何單個字元。
‘*’ 可以匹配任意字串(包括空字串)。
兩個字串完全匹配才算匹配成功。
說明:
s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字元 ? 和 *。
示例 1:
輸入:
s = “aa”
p = “a”
輸出: false
解釋: “a” 無法匹配 “aa” 整個字串。
輸入:
s = “aa”
p = ""
輸出: true
解釋: '’ 可以匹配任意字串。
示例 3:
輸入:
s = “cb”
p = “?a”
輸出: false
解釋: ‘?’ 可以匹配 ‘c’, 但第二個 ‘a’ 無法匹配 ‘b’。
示例 4:
輸入:
s = “adceb”
p = “ab”
輸出: true
解釋: 第一個 ‘’ 可以匹配空字串, 第二個 '’ 可以匹配字串 “dce”.
示例 5:
輸入:
s = “acdcb”
p = “a*c?b”
輸出: false
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/wildcard-matching
解題思路:
方法一:
動態規劃
- 建立一個dp[][]儲存所有的匹配情況,用dp[i][j]表示s的前i個字元和p的前j個字元是否匹配。
- 匹配情況大致分為三種:
1.si=pi
2.pi為?號
3.pi為*號
整合後的狀態轉移方程:
確定邊界:
-
dp[0][0]=True,即當字串 s 和模式 p 均為空時,匹配成功;
-
dp[i][0]=False,即空模式無法匹配非空字串;
-
dp[0][j] 需要分情況討論:因為星號才能匹配空字串,所以只有當模式 p 的前 j 個字元均為星號時,dp[0][j] 才為真。
Java程式碼:
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];
}
}
方法二:
貪心演算法
-
因為可以匹配一個或多個字元所有n個和1個*實際上是等價的。 所有我們可以把p看成p=∗ u1∗u2∗u3∗u4∗u5∗u6∗
-
演算法的本質是首先在s中找到u1然後依次找到u2,u3…
此外還有兩種情況:
- 模式 p 的開頭字元不是星號;
- 模式 p 的結尾字元不是星號。
第二種情況處理起來並不複雜。如果模式 p 的結尾字元不是星號,那麼就必須與字串 s 的結尾字元匹配。那麼我們不斷地匹配 s 和 p 的結尾字元,直到 p 為空或者 p 的結尾字元是星號為止。在這個過程中,如果匹配失敗,或者最後 p 為空但 s 不為空,那麼需要返回 False。
第一種情況的處理也很類似,我們可以不斷地匹配 s 和 p 的開頭字元。下面的程式碼中給出了另一種處理方法,即修改 sRecord 和 tRecord 的初始值為 −1,表示模式 p 的開頭字元不是星號,並且在匹配失敗時進行判斷,如果它們的值仍然為 −1,說明沒有「反悔」重新進行匹配的機會。
Java程式碼:
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=='?';
}
}