(28) 44. 通配符匹配 (F)

题目链接:
https://leetcode-cn.com/problems/wildcard-matching/
难度:困难
44. 通配符匹配
给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
	s 可能为空,且只包含从 a-z 的小写字母。
	p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例:
	输入:
		s = "aa"
		p = "a"
	输出: false
	解释: "a" 无法匹配 "aa" 整个字符串。
示例:
	输入:
		s = "acdcb"
		p = "a*c?b"
	输出: false

不会! 好难。。。 只是勉强看懂的动态规划的方法 类似的题目之前遇到过 好像是第十题来着 也是动态规划 忘记了。。
虽然知道是动态规划方法 但是公式找错了

正确的转移方程:
s[i]==p[j] || p[j]=='?'    dp[i][j]=dp[i-1][j-1] 
p[j]=='*'                  dp[i][j]= dp[i-1][j]|| dp[i][j-1]
其他                     false

还要考虑临界状态
	1 当字符串 s 和模式 p 均为空  dp[0][0]=true
	2 模式p为空 字符串非空      dp[i][0]=false
	3 p 的前j个字符均为星号时,dp[0][j]=true   
class Solution {
public:
    bool isMatch(string s, string p) {
        int m=s.size();
        int n=p.size();
        vector<vector<bool>> dp(m + 1, vector<bool>(n + 1));
        dp[0][0]=true;
        for (int i=1;i<n+1;i++){
            if (p[i - 1] == '*') {
                dp[0][i]=true;
            }else{
                break;
            }
        }
        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];
                }else if(p[j-1]=='?'||p[j-1]==s[i-1]){
                    dp[i][j] = dp[i - 1][j - 1];
                }
            }
        }
        return dp[m][n];
    }
};

以下两种方法没看懂 这道题好难啊 以后在看( 做个标记 设置为转载,什么时候看懂了在重新写一下,取消标记设为原创 。。。。)

贪心策略

class Solution {
public:
    bool isMatch(string s, string p) {
        auto allStars = [](const string& str, int left, int right) {
            for (int i = left; i < right; ++i) {
                if (str[i] != '*') {
                    return false;
                }
            }
            return true;
        };
        auto charMatch = [](char u, char v) {
            return u == v || v == '?';
        };

        while (s.size() && p.size() && p.back() != '*') {
            if (charMatch(s.back(), p.back())) {
                s.pop_back();
                p.pop_back();
            }
            else {
                return false;
            }
        }
        if (p.empty()) {
            return s.empty();
        }

        int sIndex = 0, pIndex = 0;
        int sRecord = -1, pRecord = -1;
        while (sIndex < s.size() && pIndex < p.size()) {
            if (p[pIndex] == '*') {
                ++pIndex;
                sRecord = sIndex;
                pRecord = pIndex;
            }
            else if (charMatch(s[sIndex], p[pIndex])) {
                ++sIndex;
                ++pIndex;
            }
            else if (sRecord != -1 && sRecord + 1 < s.size()) {
                ++sRecord;
                sIndex = sRecord;
                pIndex = pRecord;
            }
            else {
                return false;
            }
        }
        return allStars(p, pIndex, p.size());
    }
};

在leetcode评论区中无意中看到的,很强,但是我没看懂 记录

class Solution {
public:
    bool isMatch(string s, string p) {
        int i = 0, j = 0, iStar = -1, jStar = -1, m = s.size(), n = p.size();
        while (i < m) {
            if (j < n && (s[i] == p[j] || p[j] == '?')) {
                ++i, ++j;//i,j向后瞬移
            } else if (j < n && p[j] == '*') {//记录如果之后序列匹配不成功时, i和j需要回溯到的位置
                iStar = i;//记录星号
                jStar = j++;//记录星号 并且j移到下一位 准备下个循环s[i]和p[j]的匹配
            } else if (iStar >= 0) {//发现字符不匹配且没有星号出现 但是istar>0 说明可能是*匹配的字符数量不对 这时回溯
                i = ++iStar;//i回溯到istar+1 因为上次从s串istar开始对*的尝试匹配已经被证明是不成功的(不然不会落入此分支) 所以需要从istar+1再开始试 同时inc istar 更新回溯位置
                j = jStar + 1;//j回溯到jstar+1 重新使用p串*后的部分开始对s串istar(这个istar在上一行已经inc过了)位置及之后字符的匹配 
            } else return false;
        }
        while (j < n && p[j] == '*') ++j;//去除多余星号
        return j == n;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值