Leetcode 44. Wildcard Matching

Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for ‘?’ and ‘*’.

‘?’ Matches any single character.
‘*’ Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).

Note:

s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like ? or *.
Example 1:

Input:
s = “aa”
p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.
Example 2:

Input:
s = “aa”
p = “*”
Output: true
Explanation: ‘*’ matches any sequence.
Example 3:

Input:
s = “cb”
p = “?a”
Output: false
Explanation: ‘?’ matches ‘c’, but the second letter is ‘a’, which does not match ‘b’.
Example 4:

Input:
s = “adceb”
p = “*a*b”
Output: true
Explanation: The first ‘*’ matches the empty sequence, while the second ‘*’ matches the substring “dce”.
Example 5:

Input:
s = “acdcb”
p = “a*c?b”
Output: false
解析:
通配符匹配,这里?匹配一个字符,*匹配一个序列。与正则表达式匹配有些不同。
解法1:双指针法
分别定义两个指针sp和pp分别指向字符和pattern,然后分情况进行判断,如果对应位置的字符相等或者pattern在pp处的字符为?则两个指针分别递增;如果pattern当前位置为*,则定义star_index记录pattern的位置,同时定义match定义对应匹配位置的字符下标。如果star_index不为-1.表示上一个位置是*,字符指针sp进行递增,否则则返回false,如果pattern有剩余,且均为*则直接递增pp,最后判断pp与pattern长度是否相等。
具体代码如下:

class Solution {
public:
    bool isMatch(string s, string p) {
        int sp = 0;//指向字符的指针
        int pp = 0;//指向pattern的指针
        int match = 0;//匹配*的字符的位置
        int star_index = -1;//pattern中*的位置
        while(sp < s.size())
        {
            if(pp < p.size() && (s[sp] == p[pp] || p[pp] == '?'))
               {
                   sp ++;
                   pp ++;
               }else if(pp < p.size() && p[pp] == '*')
               {
                   star_index = pp;
                   match = sp;
                   pp ++;
               }else if(star_index != -1)
               {
                   pp = star_index +1;
                   match ++;
                   sp = match;
               }else
                    return false;
        }
        while(pp < p.size() && p[pp] == '*')
            pp ++;
        return pp == p.size();
    }
};

运行结果:
解法2:动态规划
此题目动态规划解法类似于Regular Expression Matching
那么先来定义dp数组吧,我们使用一个二维 dp 数组,其中 dp[i][j] 表示 s中前i个字符组成的子串和p中前j个字符组成的子串是否能匹配。大小初始化为 (m+1) x (n+1),加1的原因是要包含 dp[0][0] 的情况,因为若s和p都为空的话,也应该返回 true,所以也要初始化 dp[0][0] 为 true。还需要提前处理的一种情况是,当s为空,p为连续的星号时的情况。由于星号是可以代表空串的,所以只要s为空,那么连续的星号的位置都应该为 true,所以我们现将连续星号的位置都赋为 true。然后就是推导一般的状态转移方程了,如何更新 dp[i][j],首先处理比较 tricky 的情况,若p中第j个字符是星号,由于星号可以匹配空串,所以如果p中的前 j-1 个字符跟s中前i个字符匹配成功了( dp[i][j-1] 为true)的话,那么 dp[i][j] 也能为 true。或者若p中的前j个字符跟s中的前i-1个字符匹配成功了( dp[i-1][j] 为true )的话,那么 dp[i][j] 也能为 true(因为星号可以匹配任意字符串,再多加一个任意字符也没问题)。若p中的第j个字符不是星号,对于一般情况,我们假设已经知道了s中前 i-1 个字符和p中前 j-1 个字符的匹配情况(即 dp[i-1][j-1] ),那么现在只需要匹配s中的第i个字符跟p中的第j个字符,若二者相等( s[i-1] == p[j-1] ),或者p中的第j个字符是问号( p[j-1] == ‘?’ ),再与上 dp[i-1][j-1] 的值,就可以更新 dp[i][j] 了。
参见代码如下:

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, false));
        dp[0][0] = true;
        for(int i = 0; i < p.size(); i++)
        {
            if(p[i] == '*' && dp[0][i])
                dp[0][i+1] = true;
        }
        for(int i =0; i < m; i++)
        {
            for(int j =0; j < n; j++)
            {
                if(p[j] == '*')
                {
                    dp[i+1][j+1] = dp[i+1][j] || dp[i][j+1];
                    
                }else
                {
                    dp[i+1][j+1] = (s[i]==p[j] || p[j] =='?') && dp[i][j];
                }
            }
        }
        return dp[m][n];
    }
};

参考: https://leetcode.com/problems/wildcard-matching/discuss/17810/Linear-runtime-and-constant-space-solution https://www.cnblogs.com/grandyang/p/4401196.html https://www.youtube.com/watch?v=-8QnRMyHo_o </vector

Add a Comment

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据