LeetCode 44. 通配符匹配

Posted hlk09

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 44. 通配符匹配相关的知识,希望对你有一定的参考价值。

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 ‘?‘ 和 ‘*‘ 的通配符匹配。

‘?‘ 可以匹配任何单个字符。
‘*‘ 可以匹配任意字符串(包括空字符串)。

两个字符串完全匹配才算匹配成功。

说明:

  • 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 = "*a*b"
输出: true
解释: 第一个 ‘*‘ 可以匹配空字符串, 第二个 ‘*‘ 可以匹配字符串 "dce".

示例 5:

输入:
s = "acdcb"
p = "a*c?b"
输入: false

这个题在很多个Tag下,如DP,贪心,回溯等。

动态规划

对于两个字符串的问题,容易想到用dp[i][j]这样的形式来表示状态。我一开始是定义dp[i][j]为字符串s中前i个字符和p中前j个字符是否匹配(i和j从0开始),由于初始化问题弄了很久,最后写出的代码异常垃圾。。。

class Solution {
public:
    bool isMatch(string s, string p) {
        if (p.size() == 0 && s.size() == 0) {
            return true;
        }
        if (p.size() == 0) {
            return false;
        }
        else if (p == "*") {
            return true;
        }
        else if (s.size() == 0) {
            return false;
        }
        int row = p.size(), column = s.size();
        vector<vector<int>> dp(row);
        vector<bool> okDp(row, false);
        for (int i = 0; i < row; i++) {
            dp[i].resize(column);
        }
        bool matched = false;
        dp[0][0] = (p[0] == * || p[0] == ? || p[0] == s[0]) ? 1 : 0;
        if (p[0] == ? || p[0] == s[0]) {
            matched = true;
        }
        for (int i = 1; i < row; i++) {
            if (p[i] == *) {
                dp[i][0] = dp[i - 1][0];
                if (dp[i][0]) {
                    okDp[i] = true;
                }
            }
            else if (p[i - 1] == * && p[i] == s[0]) {
                dp[i][0] = matched ? 0 : dp[i - 1][0];
                matched = true;
            }
            else if (p[i] == ?) {
                dp[i][0] = matched ? 0 : dp[i - 1][0];
                matched = true;
            }
        }
        for (int j = 1; j < column; j++) {
            if (p[0] == *) {
                dp[0][j] = 1;
            }
        }
        for (int i = 1; i < row; i++) {
            for (int j = 1; j < column; j++) {
                if (isalpha(s[j]) && isalpha(p[i])) {
                    if (s[j] == p[i]) {
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                    else {
                        dp[i][j] = 0;
                    }
                }
                else if (p[i] == ?) {
                    dp[i][j] = dp[i - 1][j - 1];
                }
                else if (p[i] == *) {
                    if (okDp[i] || dp[i - 1][j]) {
                        okDp[i] = true;
                        dp[i][j] = 1;
                    }
                }
            }
        }
        return dp[row - 1][column - 1];
    }
};

后来学习了其他的解法,先上代码:

class Solution {
public:
    bool isMatch(string s, string p) 
    {
        int n=s.size();
        int m=p.size();
        //代表的是  s[0...i]  p[0..j]是否匹配的情况
        vector<vector<bool>>dp(n+1,vector<bool>(m+1,false));
        dp[0][0]=true;   
        for(int j=1;j<=m;j++)
            dp[0][j]=(p[j-1]==*?dp[0][j-1]:0);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if(i>0&&(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-1][j-1]||dp[i-1][j]||dp[i][j-1];         
                }
                else 
                    dp[i][j]=0;
            } 
                
                               
        return dp[n][m];
    }
                               
};

在这里,状态dp[i][j]是从1开始计算起来的。一开始不明白为什么这样子也行得通,后来考虑到有空串的情况。如""和""对于dp[0][0],""和"*"对于dp[0][1]。这样子的话初始化就很容易了。

在填表的过程中:

  1. 如果s[i - 1] = p[j - 1],则是字母匹配到了字母,那么匹配结果取决于前面的匹配结果。
  2. 如果p[j - 1] = ‘?‘,那么是问号匹配到了字母,也是匹配结果取决于前面的结果。
  3. 如果p[j - 1] = ‘*’,那么是遇到了星号。星号可能匹配的是空串,那么就是取决于dp[i][j - 1]的结果。如果匹配了一个字符,那么就是取决于dp[i - 1][j - 1]。如果匹配了两个字符,那么就是取决于dp[i - 2][j - 1]。
    所以,dp[i][j] = dp[i][j - 1] || dp[i - 1][j - 1] || dp[i - 2][j - 1] || ... || dp[0][j - 1]。
    又因为dp[i - 1][j] = dp[i - 1][j - 1] || dp[i - 2][j - 1] || ... || dp[0][j - 1]。
    所以dp[i][j] = dp[i][j - 1] || dp[i - 1][j]。



以上是关于LeetCode 44. 通配符匹配的主要内容,如果未能解决你的问题,请参考以下文章

[leetcode]44. 通配符匹配

44. LeetCode 通配符匹配

Leetcode44. 通配符匹配(动态规划)

LeetCode(44): 通配符匹配

LeetCode 44. 通配符匹配

Leetcode No.44 通配符匹配