[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;
    }
};

  

posted @ 2013-09-23 22:13  阿牧遥  阅读(2097)  评论(0编辑  收藏  举报