LeetCode Wildcard Matching

class Solution {
public:
    bool isMatch(const char *s, const char *p) {
        if (s == NULL || p == NULL) return false;
        int slen = 0;
        int plen = 0;
        
        while (s[slen] != '\0') slen++;
        while (p[plen] != '\0') plen++;
        
        if (slen == 0 && plen == 0) return true;
        if (plen == 0) return false;
        
        int si = 0;
        int pi = 0;
        int ppi = -1;
        int psi = 0;
        
        while (si < slen) {
            if (s[si] == p[pi] || p[pi] == '?') {
                si++, pi++;
            } else if (p[pi] == '*') {
                ppi = pi++;
                psi = si;
            } else if (ppi != -1){
                pi = ppi + 1;
                si = ++psi;
            } else {
                return false;
            }
        }

        while (p[pi] == '*') pi++;
        return pi == plen;
    }
};

 真写不出这样的代码。

参考:http://www.cnblogs.com/zhuli19901106/p/3572736.html

 

下面是自己写的记忆搜索代码,TLE了

class Solution {
private:
    char* memo;
    int slen;
    int plen;
public:
    bool isMatch(const char *s, const char *p) {
        slen = strlen(s);
        plen = strlen(p);
        
        memo = new char [(slen+1) * (plen+1)];
        for (int i=(slen+1) * (plen+1) - 1; i>=0; i--) memo[i] = -1;
        bool ret = dfs(s, 0, p, 0);
        delete[] memo;
        return ret;
    }
    
    bool dfs(const char* s, int spos, const char* p, int ppos) {
        int idx = ppos * slen + spos;
        if (memo[idx] >= 0) return memo[idx];
        
        if (s[spos] == '\0' && p[ppos] == '\0') return true;
        if (p[ppos] == '\0') return false;
        if (s[spos] == '\0') {
            int i = ppos;
            for (; p[i] != '\0'; i++) {
                if (p[i] != '*') break;
            }
            memo[idx] = p[i] == '\0';
            return memo[idx];
        }
        
        
        bool ret = false;

        if (p[ppos] == '?') {
            ret = dfs(s, spos + 1, p, ppos + 1);
        } else if (p[ppos] == '*') {
            for (int i=0; s[spos + i] != '\0'; i++) {
                if (dfs(s, spos + i, p, ppos + 1)) {
                    ret = true;
                    break;
                }
            }
        } else if (p[ppos] == s[spos]) {
            ret = dfs(s, spos + 1, p, ppos + 1);
        }
        memo[idx] = ret;
        return ret;
    }
};

 

第二轮:

再理解一下,source字符串和pattern字符串,设有两个指针si, pi分别指向source和pattern,

1. 如果遇到普通字符和?则依次匹配,即si++, pi++,如果此时发生失配且前面没有*出现,则此时已经无可奈何,匹配失败

2. 如果遇到有*,则记录此时的si为psi,pi为ppi。如字符串:

    abcddde

    ab*d?

    前面的ab匹配完成时,在pattern中遇到*,*可以匹配任意长度的字符,即可以产生以下几种尝试:

    1. ab cddde <-----> ab d?   (忽略*,即*匹配零个字符,si = psi,       pi = ppi + 1)

    2. ab ddde <------> ab d?  (*代替一个c,                    si = psi + 1,  pi = ppi + 1)

    3. ab dde <-------> ab d? (*代替cd,                          si = psi + 2, pi = ppi + 1)

    4. ab de <--------> ab d? (*代替cdd,                        si = psi + 3,  pi = ppi + 1)

    ...

由于我们记录了发现*时的索引,当我们在后续的尝试中失败时可以换另一种进行尝试。比如上述列表中1尝试失败时,可以立即尝试2中的情况,如此继续下去。 

又默写了一遍,算题真是无奈。

有写了一次还是不流畅,函数签名换了

 1 class Solution {
 2 public:
 3     bool isMatch(string s, string p) {
 4         int slen = s.size();
 5         int plen = p.size();
 6         s = s+"_";
 7         p = p+"_";
 8         int si = 0;
 9         int pi = 0;
10         int wpi = -1;
11         int wsi = -1;
12         
13         while (si < slen) {
14             if (s[si] == p[pi] || p[pi] == '?') {
15                 si++, pi++;
16             } else if (p[pi] == '*') {
17                 wsi = si;
18                 wpi = pi++;
19             } else if (wpi != -1) {
20                 si = ++wsi;
21                 pi = wpi + 1;
22             } else {
23                 return false;
24             }
25         }
26         
27         while (pi < plen) {
28             if (p[pi++] != '*') {
29                 return false;
30             }
31         }
32         
33         return true;
34     }
35 };

 再来,凡人只能勤加练习

// 10:15
// abcdef$
// ab$
class Solution {
public:
    bool isMatch(string s, string p) {
        
        int slen = s.size();
        int plen = p.size();
        
        s.push_back('$');
        p.push_back('$');
        
        int si = 0;
        int pi = 0;
        
        int psi = -1;
        int ppi = -1;
        
        while (si < slen) {
            if (s[si] == p[pi] || p[pi] == '?') {
                si++, pi++;
            } else if (p[pi] == '*') {
                psi = si;
                ppi = ++pi;
            } else if (psi != -1) {
                si = ++psi;
                pi = ppi;
            } else {
                return false;
            }
        }
        
        while (pi < plen) {
            if (p[pi++] != '*') {
                return false;
            }
        }
        return true;
    }
};

这里向末尾加入截止符可以避免一些边界上的处理,但必须是字符串中不会出现的,在C里面可以选择使用'\0',其实C++里也可以push_back进去,不过这样太奇葩。

posted @ 2014-07-26 23:43  卖程序的小歪  阅读(216)  评论(0编辑  收藏  举报