Leetcode每日一题:44.wildcard-matching(通配符匹配)_编程题
Leetcode每日一题:44.wildcard-matching(通配符匹配)_字符串_02
方法一:动态规划

m,n分别为s,p字符串长度,dp[i][j]代表s前i个字符与p前j个字符是否匹配;
1. dp[0][0] = true;两个字符串长度都为0,肯定是匹配的;
2. dp[0][1] 到 dp[0][k]true:代表字符串前面有连续的k个' * ',这些都是匹配的,因为 ’ * ‘可以代替空字符串,比如"""***"3. 若s[i-1]==p[j-1] 或者 p[j-1]==?则这两个字符是匹配的,即dp[i][j]与dp[i-1][j-1]的匹配情况一致;
4. 若p[j-1]=='*';因为 '*'可以代表空字符或者非空字符,所以它代表空字符串时,dp[i][j]=dp[i][j-1];代表非空字符时dp=dp[i-1][j];

notice:这并不是对应下标进行比较的,而是双循环,把所有情况都列出来
Leetcode每日一题:44.wildcard-matching(通配符匹配)_编程题_03

bool isMatch(string s, string p)
{
    int i = 0, j = 0, m = s.length(), n = p.length(); //dp[i][j]代表s的前i个字符,p的前j个字符能够匹配;

    bool dp[m + 1][n + 1];
    for (int i = 0; i <= m; i++) //初始化全部为false
    {
        for (int j = 0; j <= n; j++)
        {
            dp[i][j] = false;
        }
    }

    dp[0][0] = true;
    for (int k = 1; k <= n; k++) //将前面k个连续的'*'对应的dp[0][k]置为true
    {
        if (p[k - 1] == '*')
            dp[0][k] = true;
        else
        {
            break;
        }
    }
    //双循环,注意这里的 i,j 表示对应字符串 s 前i个字符 与 p 前j个字符是否匹配 他们转化为下标时时i-1 和 j-1for (i = 1; i <= m; i++)
    {
        for (j = 1; j <= n; j++)
        {
            if (s[i - 1] == p[j - 1] || p[j - 1] == '?')
            {
                dp[i][j] = dp[i - 1][j - 1];
            }
            else if (p[j - 1] == '*')
            {
                dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
            }
        }
    }
    return dp[m][n];
}

方法二:贪心 + 双指针 (回溯法)
利用双指针 istar 和 jstar 来存储匹配不成功后需要回溯的位置,多次匹配只有在字符串p中出现’ * '之后;
Leetcode每日一题:44.wildcard-matching(通配符匹配)_字符串_04
因为它并不是玩玩全全的双循环,只是在一个循环中可能要在进行一个部分循环,所以复杂度必定低于动态规划;

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;//记录当p[j]==*‘时,i此时的位置
                jStar = j++;//记录j的位置 并且j移到下一位 准备次s[i]和p[j]的匹配
            } 
            else if (iStar >= 0) 
            {//发现字符不匹配且没有星号出现 但是istar>0 说明可能是*匹配的字符数量不对 这时回溯
                i = ++iStar;//i回溯到istar+1 因为上次从s串istar开始对*的尝试匹配已经被证明后面存在不匹配情况(不然不会落入此分支) 所以需要从istar+1再次开始试 同时 istar 更新回溯位置,就是找到下一个s[istar]==p[jstar+1]中istar的位置
                j = jStar + 1;//j回溯到jstar+1 并保持位置 直到s[istar]==p[j]时重新开始匹配
            } else return false;
        }
        while (j < n && p[j] == '*') ++j;//去除剩下多余的星号
        return j == n;//如果星号后还有非星号字符,则j != n ,则返回false;否则返回true;
}