题目链接:Multiply Strings

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). The function prototype should be: bool isMatch(const char *s, const char *p) Some examples: isMatch("aa","a") → false isMatch("aa","aa") → true isMatch("aaa","aa") → false isMatch("aa", "*") → true isMatch("aa", "a*") → true isMatch("ab", "?*") → true isMatch("aab", "c*a*b") → false 

这道题的要求是通配符匹配。其中模式串中可以包含‘?’和‘*’,‘?’可以匹配单个任意字符,‘*’可以匹配任意字符串(包括空串)。

1. 递归回溯

看到这道题,首先想到递归回溯处理。

当s和p当前字符相同或者p当前字符为‘?’的时候,说明s和p当前匹配,则s和p同时后移一步。

当p当前字符为‘*’的时候,说明可以匹配任意多个s中的后序子串,因此需要递归s每一种情况,如果成功匹配,返回true;否则,回溯递归检查s的下一子串。

终止条件就是s或p到达字符串尾部。

代码如下,可惜TLE。。。

时间复杂度:O(???)

空间复杂度:O(???)

 1 class Solution 2 { 3 public: 4     bool isMatch(const char *s, const char *p) 5     { 6         if(*s == '\0' && *p == '\0') 7             return true; 8  9         if(*s == '\0' || *p == '\0')10             return false;11 12         if(*s == *p || '?' == *p)13             return isMatch(++ s, ++ p);14 15         if('*' == *p)16         {17             int ls = strlen(s), lp = strlen(p);18             for(int i = 0; i < ls - lp + 1; ++ i)19                 if(isMatch(s + i, p + 1));20                     return true;21         }22 23         return false;24     }25 };

2. 迭代回溯

于是乎考虑非递归进行回溯,即,在s和p右移的时候,当p的当前字符为‘*’时,用ss和pp两个指针记录一下当前位置;当没有匹配的时候,s和p回溯到ss和pp位置的下一位置。就这样直到s到达字符串尾部。

注意一下,当s到达尾部的时候,p可能没有到达尾部。此时需要检测p的剩余字符是否全为‘*’:如果是,返回true;否则,返回false。

AC了。。。

时间复杂度:O(???)

空间复杂度:O(1)

 1 class Solution 2 { 3 public: 4     bool isMatch(const char *s, const char *p) 5     { 6         const char *ss = s, *pp = NULL; 7         while('\0' != *s) 8         { 9             if('?' == *p || *s == *p)10                 ++ s, ++ p;11             else if('*' == *p)12                 ss = s, pp = p ++;13             else if(pp != NULL)14                 s = ++ ss, p = pp + 1;15             else16                 return false;17         }18 19         while('*' == *p)20             ++ p;21 22         return '\0' == *p;23     }24 };

3. 动态规划(一)

当然,这种题,还可以用动态规划的思路处理。用bool型二维数组vvb[i][j]表示s的前i个字符和p的前j个字符是否匹配。

初始值,vvb[0][0]为true,vvb[0][j]的值取决于p前一个位置是否为‘*’以及前一情况是否匹配。

当p[j]等于‘?’或者s[i]等于p[j]时,则vvb[i][j]的值取决于vvb[i-1][j-1],即为s的前一位置和p的前一位置是否匹配;

当p[j]等于‘*’时,如果该‘*’可以匹配s中的0个或者1个字符,分别对应vvb[i][j-1],即s的当前位置和p的前一位置是否匹配,以及vvb[i-1][j-1],即s的前一位置和p的前一位置是否匹配。

可惜MLE,看了数据量不小啊。。。

时间复杂度:O(ls*lp)(ls和lp分别为s和p字符串的长度)

空间复杂度:O(ls*lp)

 1 class Solution 2 { 3 public: 4     bool isMatch(const char *s, const char *p) 5     { 6         int ls = strlen(s), lp = strlen(p); 7         vector<vector<bool> > vvb(ls + 1, vector<bool>(lp + 1, false)); 8         vvb[0][0] = true; 9 10         for(int j = 1; j <= lp; ++ j)11         {12             vvb[0][j] = vvb[0][j - 1] && '*' == p[j - 1];13             for(int i = 1; i <= ls; ++ i)14             {15                 if('?' == p[j - 1] || s[i - 1] == p[j - 1])16                     vvb[i][j] = vvb[i - 1][j - 1];17                 else if('*' == p[j - 1])18                     vvb[i][j] = vvb[i][j - 1] || vvb[i - 1][j - 1];19             }20         }21 22         return vvb[ls][lp];23     }24 };

4. 动态规划(二)

由于判断当前能否匹配的时候,只是用到了前一情况的结果,因此可以申请一维数组vb[i],表示s的前i个字符和p的前j个字符是否匹配。

当p[j]不是‘*’的时候,只要判断如果当前s[i-1]和p[j-1]上的字符是否匹配,并且vb[i-1]是否为true; 这里可以考虑从后往前遍历s,这样vb[i-1]就是前一情况。

当p[j]是‘*’的时候,因为‘*’可以匹配任意字符串,所以在前面的vb[i]只要有true,那么剩下i后面就都是true了。

还是TLE,因为最后一组数据过不了,好多童鞋选择跳过这组数据了。。。

时间复杂度:O(ls*lp)(ls和lp分别为s和p字符串的长度)

空间复杂度:O(ls*lp)

 1 class Solution 2 { 3 public: 4     bool isMatch(const char *s, const char *p) 5     { 6         int ls = strlen(s), lp = strlen(p); 7  8         vector<bool> vb(ls + 1, false); 9         vb[0] = true;10 11         for(int j = 1; j <= lp; ++ j)12         {13             if('*' != p[j - 1])14                 for(int i = ls; i > 0; -- i)15                     vb[i] = vb[i - 1] && ('?' == p[j - 1] || s[i - 1] == p[j - 1]);16             else17             {18                 int i;19                 for(i = 0; i <= ls && !vb[i]; ++ i);20                 for( ; i <= ls; ++ i)21                     vb[i] = true;22             }23             vb[0] = vb[0] && '*' == p[j - 1];24         }25 26         return vb[ls];27     }28 };

4. 贪心法

未完待续。。。

时间复杂度:O()

空间复杂度:O()