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进去,不过这样太奇葩。