[leetcode]Wildcard Matching

难题。一开始使用递归+备忘录的方式,我的递归写的太烂,大数据集合超时。要注意的是,一开始没考虑到"", "*"的case。超时的代码(即使后来加上长度的预先判断):

class Solution {

public:

    int matrix[1000][1000];

    bool isMatch(const char *s, const char *p) {

        int slen = strlen(s);

        int plen = strlen(p);

        const char* tmp = p;  

        int cnt = 0;  

        while (*tmp != '\0') if (*(tmp++) != '*') cnt++;  

        if (cnt > slen) return false;  

        memset(matrix, 0, sizeof(matrix));

        int r = isMatch(s, 0, slen, p, 0, plen);

        return (r == 1);

    }

     

private:

    int isMatch(const char *s, int i, int slen, const char *p, int j, int plen)

    {

        if (matrix[i][j] != 0) return matrix[i][j];

        if (i == slen && j == plen) return 1;

        if (j == plen) return -1;

        if (i == slen && p[j] == '*')

        {

            matrix[i][j] = isMatch(s, i, slen, p, j+1, plen);

            return matrix[i][j];

        }

        if (p[j] == '?' || p[j] == s[i])

        {

            matrix[i][j] = isMatch(s, i+1, slen, p, j+1, plen);

            return matrix[i][j];

        }

        if (p[j] == '*')

        {

            bool r = isMatch(s, i+1, slen, p, j, plen) == 1

                || isMatch(s, i, slen, p, j+1, plen) == 1;

            matrix[i][j] = r ? 1:-1;

            return matrix[i][j];

        }

        else

        {

            matrix[i][j] = -1;

            return matrix[i][j];

        }

    }

};  

参考里看到一个概念好的递归代码 http://discuss.leetcode.com/questions/222/wildcard-matching,虽然也大数据超时。精华部分是,如果遇到‘*’,那么s向右的任何一段子串和p跳过‘*’后的匹配成功都算成功:

class Solution {

public:

    bool isMatch(const char *s, const char *p) {

        if (*p == '*'){//return true;

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

            if (*p == '\0') return true;

            while(*s != '\0' && !isMatch(s,p)){

                ++s;                

            }

            return *s != '\0';

        }

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

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

        else return false;

    }

};

但即使将上述方法转成备忘录模式,也超时。递归还是太多了。必须自底向上DP来做,总的来说,DP才是正道。这里有个很好的文章:http://www.iteye.com/topic/1131749 还有 http://blog.csdn.net/a83610312/article/details/9750655

下面是DP的代码:

class Solution {

public:

    bool matrix[500][500];

    bool isMatch(const char *s, const char *p) {

        int slen = strlen(s);

        int plen = strlen(p);

         

        const char* tmp = p;  

        int cnt = 0;  

        while (*tmp != '\0') if (*(tmp++) != '*') cnt++;  

        if (cnt > slen) return false;  



        memset(matrix, 0, sizeof(matrix));

        matrix[0][0] = true; // i,j means length

        for (int i = 1; i <= plen; i++)

        {

            if (matrix[0][i-1] && p[i-1] == '*') matrix[0][i] = true;

            for (int j = 1; j <= slen; j++)

            {

                if (p[i-1] == '*')

                {

                    matrix[j][i] = (matrix[j-1][i] || matrix[j][i-1]);

                }

                else if (p[i-1] == '?' || p[i-1] == s[j-1])

                {

                    matrix[j][i] = matrix[j-1][i-1];

                }

                else

                {

                    matrix[j][i] = false;

                }

            }

        }

        return matrix[slen][plen];

    }

};

其实DP是自然的,但是如果不用一开始的长度判断,依然会超时。

其实长度判断也属于一种剪枝吧,用O(n)的复杂度判断对O(n^2)的DP剪枝,是很大的改善。

由于F[i][j]只和上两个状态有关,所以可使用滚动数组省空间。

网上也有用贪心的,可再研究。

第二刷:

关键在于,只要记录最后一个*就可以了,因为*可以匹配所有,如果*后面的没匹配上,就是*之后的问题,即使退回之前的*,情况只会更差。

class Solution {

public:

    bool isMatch(const char *s, const char *p) {

        int i = 0;

        int j = 0;

        int backup_i = -1;

        int backup_j = -1;

        while (s[i] != '\0') {

            if (s[i] == p[j] || p[j] == '?') {

                i++; j++;

            } else if (p[j] == '*') {

                backup_j = j;

                backup_i = i;

                j++;

            } else if (s[i] != p[j]) {

                if (backup_j == -1) {

                    return false;

                }

                j = backup_j;

                i = backup_i + 1;

                backup_i = i;

                j++;

            }

        }

        if (s[i] == '\0') {// && left all '*' return true;

            while (p[j] != '\0') {

                if (p[j] != '*') {

                    return false;

                }

                j++;

            }

            return true;

        }

        return false;

    }

};

  

你可能感兴趣的:(LeetCode)