【Lintcode】192. Wildcard Matching

题目地址:

https://www.lintcode.com/problem/wildcard-matching/description

给定一个字符串 s s s和一个模式串 p p p p p p中含字母,'?'或者'*'。其中'?'可以匹配任何单个字符,'*'可以匹配任意字符串,包括空串。问 s s s是否符合 p p p所代表的模式。

该题的思考方式与Regular Expression Matching这个问题非常相似,可以参考https://blog.csdn.net/qq_46105170/article/details/109213897。下面详细说明。

思路是动态规划。设 f [ i ] [ j ] f[i][j] f[i][j] s s s的前 i i i个字符和 p p p的前 j j j个字符是否匹配( i i i j j j 1 1 1开始计数),即 s [ 0 : i − 1 ] s[0:i-1] s[0:i1]是否和 p [ 0 : j − 1 ] p[0:j-1] p[0:j1]匹配。那么可以按照 p [ j − 1 ] p[j-1] p[j1]的匹配方式来分类:
1、如果 p [ j − 1 ] p[j-1] p[j1]不是'*',那必然有 s [ 0 : i − 1 ] s[0:i-1] s[0:i1]非空,并且要么 s [ i − 1 ] = p [ j − 1 ] s[i-1]=p[j-1] s[i1]=p[j1] p [ j − 1 ] p[j-1] p[j1]'?'。这样 p p p最后一个字符匹配好之后,还需要 s [ 0 : i − 2 ] s[0:i-2] s[0:i2] p [ 0 : j − 2 ] p[0:j-2] p[0:j2]也要匹配。所以有: f [ i ] [ j ] = ( s [ i − 1 ] = p [ j − 1 ] ∨ p [ j − 1 ] = ? ) ∧ f [ i − 1 ] [ j − 1 ] f[i][j]=(s[i-1]=p[j-1]\lor p[j-1]=?)\land f[i-1][j-1] f[i][j]=(s[i1]=p[j1]p[j1]=?)f[i1][j1]2、如果 p [ j − 1 ] p[j-1] p[j1]'*',那么这个'*'有两种匹配方式,一种是匹配空串,那么能匹配当前仅当 s [ 0 : i − 1 ] s[0:i-1] s[0:i1] p [ 0 : j − 2 ] p[0:j-2] p[0:j2]能匹配,也就是看 f [ i ] [ j − 1 ] f[i][j-1] f[i][j1];另一种是匹配非空串,那么将 s [ i − 1 ] s[i-1] s[i1]删掉之后需要继续和 p [ 0 : j − 1 ] p[0:j-1] p[0:j1]匹配,即需要 s [ 0 : i − 2 ] s[0:i-2] s[0:i2] p [ 0 : j − 1 ] p[0:j-1] p[0:j1]要匹配,也就是看 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j]。所以有: f [ i ] [ j ] = f [ i ] [ j − 1 ] ∨ f [ i − 1 ] [ j ] f[i][j]=f[i][j-1]\lor f[i-1][j] f[i][j]=f[i][j1]f[i1][j]接下来考虑初始条件,首先空串可以和空模式匹配,但非空串不能喝空模式匹配,所以有 f [ 0 ] [ 0 ] f[0][0] f[0][0]是true,但当 i > 0 i>0 i>0,则 f [ i ] [ 0 ] f[i][0] f[i][0]是false。而空串是否能匹配非空模式,这一点是无法看出的,需要在递推的过程中得出。代码如下:

public class Solution {
    /**
     * @param s: A string
     * @param p: A string includes "?" and "*"
     * @return: is Match?
     */
    public boolean isMatch(String s, String p) {
        // write your code here
        boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
        
        for (int i = 0; i <= s.length(); i++) {
            for (int j = 0; j <= p.length(); j++) {
            	// 空串可以匹配空模式,非空串无法匹配空模式
                if (i == 0 && j == 0) {
                    dp[i][j] = true;
                } else if (j == 0) {
                    dp[i][j] = false;
                } else {
                	// 如果模式串非空,考虑模式串最后一个字符是不是'*';
                    if (p.charAt(j - 1) != '*') {
                    	// 如果模式串最后一位不是'*',那么匹配当且仅当s非空,并且最后一个字符可以匹配,并且之前也可以匹配
                        if (i > 0 && (p.charAt(j - 1) == s.charAt(i - 1) || p.charAt(j - 1) == '?')) {
                            dp[i][j] |= dp[i - 1][j - 1];
                        }
                    } else {
                    	// 如果模式串最后一位是'*',那么要么将其视为空串,要么就需要s非空并且除去最后一位之后得到的子串与p匹配
                        dp[i][j] |= dp[i][j - 1];
                        if (i > 0) {
                            dp[i][j] |= dp[i - 1][j];
                        }
                    }
                }
            }
        }
        
        return dp[s.length()][p.length()];
    }
}

时空复杂度 O ( l s l p ) O(l_sl_p) O(lslp)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值