LeeCode(动态规则,贪心算法)44_通配符匹配

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=='?';
    }

}

猜你喜欢

转载自blog.csdn.net/u013456390/article/details/111865076