题目链接: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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution
{
public:
    bool isMatch(const char *s, const char *p)
    {
        if(*s == '\0' && *p == '\0')
            return true;

        if(*s == '\0' || *p == '\0')
            return false;

        if(*s == *p || '?' == *p)
            return isMatch(++ s, ++ p);

        if('*' == *p)
        {
            int ls = strlen(s), lp = strlen(p);
            for(int i = 0; i < ls - lp + 1; ++ i)
                if(isMatch(s + i, p + 1));
                    return true;
        }

        return false;
    }
};
  1. 迭代回溯

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

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

AC了。。。

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

空间复杂度:O(1)

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

        while('*' == *p)
            ++ p;

        return '\0' == *p;
    }
};
  1. 动态规划(一)

当然,这种题,还可以用动态规划的思路处理。用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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution
{
public:
    bool isMatch(const char *s, const char *p)
    {
        int ls = strlen(s), lp = strlen(p);
        vector<vector<bool> > vvb(ls + 1, vector<bool>(lp + 1, false));
        vvb[0][0] = true;

        for(int j = 1; j <= lp; ++ j)
        {
            vvb[0][j] = vvb[0][j - 1] && '*' == p[j - 1];
            for(int i = 1; i <= ls; ++ i)
            {
                if('?' == p[j - 1] || s[i - 1] == p[j - 1])
                    vvb[i][j] = vvb[i - 1][j - 1];
                else if('*' == p[j - 1])
                    vvb[i][j] = vvb[i][j - 1] || vvb[i - 1][j - 1];
            }
        }

        return vvb[ls][lp];
    }
};
  1. 动态规划(二)

由于判断当前能否匹配的时候,只是用到了前一情况的结果,因此可以申请一维数组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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution
{
public:
    bool isMatch(const char *s, const char *p)
    {
        int ls = strlen(s), lp = strlen(p);

        vector<bool> vb(ls + 1, false);
        vb[0] = true;

        for(int j = 1; j <= lp; ++ j)
        {
            if('*' != p[j - 1])
                for(int i = ls; i > 0; -- i)
                    vb[i] = vb[i - 1] && ('?' == p[j - 1] || s[i - 1] == p[j - 1]);
            else
            {
                int i;
                for(i = 0; i <= ls && !vb[i]; ++ i);
                for( ; i <= ls; ++ i)
                    vb[i] = true;
            }
            vb[0] = vb[0] && '*' == p[j - 1];
        }

        return vb[ls];
    }
};
  1. 贪心法

未完待续。。。

时间复杂度:O()

空间复杂度:O()