Leetcode 44. Wildcard Matching

44. Wildcard Matching

题目链接https://leetcode.com/problems/wildcard-matching/

Description:

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 = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".

Example 2:

Input:
s = "acdcb"
p = "a*c?b"
Output: false

题意:

给出两个字符串,一个是匹配串,另一个是用来匹配的串,其中*代表任意的数,包括无数;"?"代表任意的一个字符。

现在问两个串是否能够成功匹配。

 

题解:

这题dp应该还是好做,dp[i,j]含义为第一个串匹配前i个,第二个串匹配前j个是否能够成功匹配。

初始化为dp[0,0]=1,然后转移方程为:

dp[i,j]=dp[i-1,j-1] && s[i-1]==p[j-1] || p[j-1]=="?"  ;  if(p[j-1]=="*") dp[i,j]=dp[i-1,j] || dp[i,j-1] || dp[i-1,j-1]。

对第二个式子解释一下吧,如果当前的p是"*",那么当前状态可能就由三种情况转移过来:

1."*"匹配了第i-1个字符,现在继续匹配第i个;2."*"不匹配,即当做空;3."*"作为开头来匹配第i个字符。

然后就可以做了,代码如下:

class Solution {
public:
    bool isMatch(string s, string p) {
        int n = s.length(), m = p.length();
        int dp[n+5][m+5];
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=m;i++){
            if(p[i-1]=='*'){
                dp[0][i]=1;
                continue ;
            }
            break ;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                dp[i][j]=(dp[i-1][j-1]&&(s[i-1]==p[j-1] || p[j-1]=='?'));
                if(p[j-1]=='*') dp[i][j]=(dp[i-1][j]||dp[i][j-1]||dp[i-1][j-1]);
            }
        }
        return dp[n][m];
    }
};
View Code

 

但是这里dp的复杂度是O(n^2),复杂度有点高,我们可以换一种思路来解,即指针法。

这个方法有点巧妙,类似于模拟,即定义两个i,j指针,分别在两个字符串中,现在同样有几种情况:

假设当前s[i-1]==p[j-1] || p[j-1]=="?",意即能够重新匹配,我们i++,j++;

还有一种情况就是当前的p[j-1]=="*",那么我们记录下i当前的位置,以及让j++,继续匹配。

如果出现匹配不成功的情况,那么就让j回到刚才记录的"*"之后那一位,否则无解;让i回到刚才记录i的位置的下一位继续匹配。

就不断重复这样的匹配操作,如果再一次遇到一个"*",那么我们就更换"*"的位置,采用最近的"*",这是最优的,因为这里的"*"可以看作空,也就是说既可以从之前那里匹配过来,也可以从当前这里开始匹配,这样时间复杂度会小些,不然又O(n^2)了。

以上就是该算法的大体思想,另外注意一下代码的实现,最后的时候要记得看是否两个指针都到了末尾,这样才算匹配成功。

注意一下代码的细节,建议亲自实现。

 

代码如下:

class Solution {
public:
    bool isMatch(string s, string p) {
        int n = s.length(), m = p.length();
        int i=0,j=0;
        int pre=-1,alp=-1;
        while(i<n){
            if(j<m&&(s[i]==p[j]||p[j]=='?')) i++,j++;
            else if(j<m&&p[j]=='*'){
                pre = j++;
                alp = i;
            }else if(pre>-1){
                j = pre+1;
                i = ++alp;
            }else return false ;
        }
        while(j<m && p[j]=='*') j++;
        return j==m;
    }
};
View Code

 

posted @ 2019-01-06 20:08  heyuhhh  阅读(187)  评论(0编辑  收藏  举报