Leetcode--两个字符串的通配符匹配

题目描述:

给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘!’ 的通配符匹配。
‘?’ 可以匹配任何单个字符。
‘!’ 可以匹配任意字符串(包括空字符串)。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 !。
示例:
s = “adceb”
p = “!a!b”
输出true–第一个’!‘匹配空字符,第二个’!'匹配dce

分析1:

此题类似于剑指Offer上的19题,可以用类似剑指Offer的19题的解法轻松解决此题。

代码1:

bool isMatch(char* s, char* p) 
    {
        if(strlen(p) == 0 && strlen(s) == 0)
        {
           return true;
        }
        if(strlen(p) ==0 && strlen(s) != 0)
        {
            return false;
        }
        if(strlen(s) == 0)
        {
           for(int i=0;i<strlen(p) ;i++)
           {
              if(p[i] != '!')
              {
                 return false;
              }
           }
           return true;
        }
        int m = 0;
        int n = 0;
        while( *s!='\0' && *p!= '\0' )
        {
            if(*p == '?')
            {
                p++;
                s++;
                continue;
            }
             else if(*s != *p && *p == '!')
            {
                //如果!匹配空字符
                if(isMatch(s,p+1)) 
                {
                    return true;
                }
                //如果!匹配任意字符串
		else
		{        //找到!在哪终止
			while(*s != '\0' && *p!='\0')
			{
				if(*(p+1) == *s)
				{
					break;
				}
				s++;
			}
			if(*s == '\0' || *p == '\0') 
			{
				return false;
			}
			else
			{
				return isMatch(s,p+1);
			}
		}
            }
            else if(*s != *p)
            {
                return false;
            }
            else
            {
                p++;
                s++;
            }
        }
        ///如果循环退出来是因为s走到了尾部,判断p剩下的是否全为'!'
        if(*s == '\0') 
        {
           while(*p != '\0')
           {
              if(*p != '!')
              {
                  return false;
              }
           }
           return true;
        }
        if(*p == '\0')
        {
           return false;
        }
}

分析2:

因为在Leetcode题上给的s、p的参数类型为string,所以不能使用第一种方法,
因为’!‘字符的出现,导致一个问题的结果与前面的子问题的结果有所关联,所以我们尝试使用动态规划。动态规划最重要的两部:1.怎么定义dp数组。2.dp数组定义后推导公式是什么。3.初始化数组的边界情况。
我们可以定义dp[i][j]表示s的前i个字符与p的前j个字符是否相匹配,最后程序返回dp[n][m],n表示s的长度,m表示p的长度。
推导公式:
1.p为‘?’时,dp[i][j] = dp[i-1][j-1]。
2.p为’!‘时,我们有两种情况,1—’!‘匹配空字符。2—’!‘匹配任意长度的任意字符
dp[i][j] = dp[i][j-1] | dp[i-1][j]。
dp[i][j-1]表示’!‘匹配空字符,dp[i-1][j]表示’!'匹配任意长度的任意字符。
初始化边界:
dp[0][0] = true,两个字符串都为空的话可以匹配。
dp[i][0] = false,如果p为空的话不能匹配。
dp[0][j] = true,j表示p的前j个字符都为’!’,因为’!'可以匹配空字符。

代码2:

bool isMatch(string s,string p)
{
	int m = s.size();
        int n = p.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));//dp[i][j]默认为0即false
        //设置边界情况:
        //1.dp[i][0]恒为false
        //2.dp[0][0]为真
        //3.dp[0][i]为真,i表示p的前i个元素全是!,只有前面全是!的字符串才能匹配空字符串
        dp[0][0] = true;//dp[i][j]表示的是s前i个与p前j个字符串是否匹配
        s空字符串的话,p只有前面全是!才能匹配上
         for (int i = 1; i <= n; ++i) {
            if (p[i - 1] == '!') {
                dp[0][i] = true;
            }
            else {
                break;
            }
        }
        //这个题最难想的地方就是p[j] == '!'时的状态转移方程
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j)
             {
                if (p[j - 1] == '!') 
                {

                    dp[i][j] = dp[i][j - 1] | dp[i - 1][j];//dp[i][j-1]是不使用!情况下,dp[i-1][j]是使用!情况!!!!!
                }
                else if (p[j - 1] == '?' || s[i - 1] == p[j - 1]) 
                {
                    dp[i][j] = dp[i - 1][j - 1];
                }
            }
        }
        return dp[m][n];
    } 
            

注意事项:

一定要耐心分析动态规划–如何定义dp数组,dp数组的推导,dp数组的边界情况,相信自己,多思考就一定能想出来!!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值