1. 程式人生 > 其它 >LeeCode(動態規則,貪心演算法)44_萬用字元匹配

LeeCode(動態規則,貪心演算法)44_萬用字元匹配

技術標籤:leetcode演算法javaleetcode動態規劃貪心演算法

LeeCode(動態規則,貪心演算法)44_萬用字元匹配

題目:
給定一個字串 (s) 和一個字元模式 § ,實現一個支援 ‘?’ 和 ‘*’ 的萬用字元匹配。

‘?’ 可以匹配任何單個字元。
‘*’ 可以匹配任意字串(包括空字串)。
兩個字串完全匹配才算匹配成功。

說明:

s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字元 ? 和 *。
示例 1:

輸入:
s = “aa”
p = “a”
輸出: false
解釋: “a” 無法匹配 “aa” 整個字串。

示例 2:

輸入:
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

著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

解題思路:

方法一:
動態規劃

  1. 建立一個dp[][]儲存所有的匹配情況,用dp[i][j]表示s的前i個字元和p的前j個字元是否匹配。
  2. 匹配情況大致分為三種:
    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]; } }

方法二:
貪心演算法

  1. 因為可以匹配一個或多個字元所有n個和1個*實際上是等價的。 所有我們可以把p看成p=∗ u1∗u2∗u3∗u4∗u5∗u6∗

  2. 演算法的本質是首先在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=='?';
    }

}