Leetcode | Wildcard Matching
2014-05-07 21:34
225 查看
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
递归的话会超时。
借用了discussion上面的图。m[i+1][j+1]就是p[0...i]与s[0...j]的匹配结果。
1. 如果p[i] = '?' 或者 p[i] = s[j] (暗含p[i] != '*'的意思),那么m[i+1][j+1]就是等于它的对角线左上方的位置, m[i][j]。也就是都移动了一个字符。
2. 如果p[i] = '*'。从图里面就可以看出来,从(3)走到(4),其实p[0...3]="a?c*"应该是能够匹配到s[0...j],2<=j<6。也就是说,m[4][3...6]=true;
就是从上一行找到第一个为true的位置,那么从当前行中从该位置到最后都应该设为true。
二维DP会报MLE,但是阿牧遥 用了一个dp[500][500]倒是可以通过。。。
注意第8行,如果没有这一句就会TLE。主要是计算p里面的非*的字符,如果这个数目都比s的长度大,那么肯定匹配不完。直接返回true。这是为了过一个大数据。
第一次遇到p[1]='*',从s[1]开始匹配,s[1]=p[2], 第二次遇到p[3] ='*',s[2]!=p[4],此路不通,要回溯,是不是要回溯到p[2]和s[2]呢,其实不用。
因为我们最后面撞见了p[3]='*',证明s[0...1]和p[0...2]是匹配的,那么直接从p[4]和s[3]回溯就可以了。p[4]=s[3],所以返回true。
因为遇到*都是先将*从区配空串开始的,所以当*把s都一直匹配到末尾有三种情况:
1. p后面还有,但是都是*,还是返回true;
2. p后面还有,但不全是*,返回false;
3. p后面没有,匹配刚刚好。
这里第10行,是压缩了p连续*的情况。多个*相连其实相同于一个*。backP指向的*的下一个字符。backS就是从S当前的位置开始。
third time.
'?' 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
递归的话会超时。
Method I
然后想用二维的DP。借用了discussion上面的图。m[i+1][j+1]就是p[0...i]与s[0...j]的匹配结果。
1. 如果p[i] = '?' 或者 p[i] = s[j] (暗含p[i] != '*'的意思),那么m[i+1][j+1]就是等于它的对角线左上方的位置, m[i][j]。也就是都移动了一个字符。
2. 如果p[i] = '*'。从图里面就可以看出来,从(3)走到(4),其实p[0...3]="a?c*"应该是能够匹配到s[0...j],2<=j<6。也就是说,m[4][3...6]=true;
就是从上一行找到第一个为true的位置,那么从当前行中从该位置到最后都应该设为true。
bool isMatch(const char *s, const char *p) { if (p == '\0') return (s == '\0'); int n1 = strlen(s); int n2 = strlen(p); vector<vector<bool> > m(n2 + 1, vector<bool>(n1 + 1, false)); m[0][0] = true; for (int i = 0; i < n2; ++i) { if (p[i] == '*') { int j = 0; for (j = 0; j <= n1; ++j) { if (m[i][j]) break; } if (j > n1) return false; for (int k = j; k <= n1; ++k) { m[i + 1][k] = true; } } else { for (int j = 0; j < n1; ++j) { if (p[i] == '?' || s[j] == p[i]) { m[i + 1][j + 1] = m[i][j]; } } } } return m[n2][n1]; }
二维DP会报MLE,但是阿牧遥 用了一个dp[500][500]倒是可以通过。。。
优化
因为其实每次都是更新一行,可以将两维dp改成一维的dp。将上面的代码对应转换就行,不过要注意的是,不满足条件更新值的,需要设成默认值false;class Solution { public: bool isMatch(const char *s, const char *p) { if (p == '\0') return (s == '\0'); int n1 = strlen(s); int n2 = strlen(p); int chars = 0; for(int i=0; p[i] != '\0'; ++i) if(p[i] != '*' && n1<++chars) return false; vector<bool> m(n1 + 1, false); m[0] = true; for (int i = 0; i < n2; ++i) { if (p[i] == '*') { int j = 0; for (j = 0; j <= n1; ++j) { if (m[j]) break; } for (; j <= n1; ++j) { m[j] = true; } } else { for (int j = n1 - 1; j >= 0; --j) { if (p[i] == '?' || s[j] == p[i]) { m[j + 1] = m[j]; } else { m[j + 1] = 0; } } m[0] = false; } } return m[n1]; } };
注意第8行,如果没有这一句就会TLE。主要是计算p里面的非*的字符,如果这个数目都比s的长度大,那么肯定匹配不完。直接返回true。这是为了过一个大数据。
Method II
遇到*的时候是可能需要回溯的。但是回溯是不是一定要回到回溯前的位置呢。比如s="aacb",p="a*a*b"。结果应该是为true的。第一次遇到p[1]='*',从s[1]开始匹配,s[1]=p[2], 第二次遇到p[3] ='*',s[2]!=p[4],此路不通,要回溯,是不是要回溯到p[2]和s[2]呢,其实不用。
因为我们最后面撞见了p[3]='*',证明s[0...1]和p[0...2]是匹配的,那么直接从p[4]和s[3]回溯就可以了。p[4]=s[3],所以返回true。
因为遇到*都是先将*从区配空串开始的,所以当*把s都一直匹配到末尾有三种情况:
1. p后面还有,但是都是*,还是返回true;
2. p后面还有,但不全是*,返回false;
3. p后面没有,匹配刚刚好。
lass Solution { public: bool isMatch(const char *s, const char *p) { if (p == '\0') return (s == '\0'); const char *backP = NULL, *backS = NULL; while (*s) { if (*p == '*') { while (*p != '\0' && *p == '*') p++; if (*p == NULL) return true; backS = s; backP = p; } else if (*s == *p || *p == '?') { s++; p++; } else if (backP) { s = ++backS; p = backP; } else { return false; } } while (*p) { if (*p != '*') return false; p++; } return true; } };
这里第10行,是压缩了p连续*的情况。多个*相连其实相同于一个*。backP指向的*的下一个字符。backS就是从S当前的位置开始。
third time.
class Solution { public: bool isMatch(const char *s, const char *p) { if (p == NULL || *p == '\0') return (s == NULL || *s == '\0'); const char* lastS = NULL, *lastP = NULL; while (*s != '\0') { if (*p != '\0' && (*s == *p || *p == '?')) { s++, p++; } else if (*p == '*') { for (; *p != '\0' && *p == '*'; p++); lastP = p; lastS = s; } else if (lastP != NULL) { p = lastP; s = ++lastS; } else { break; } } for (; *p != '\0' && *p == '*'; p++); return *p == '\0' && *s == '\0'; } };
相关文章推荐
- LeetCode 44. Wildcard Matching
- Leetcode: Wildcard Matching
- LeetCode Wildcard Matching
- [LeetCode] Wildcard Matching
- Leetcode_Wildcard Matching
- LeetCode | Wildcard Matching
- LeetCode – Refresh – Wildcard Matching
- leetcode 44. Wildcard Matching
- LEETCODE: Wildcard Matching
- leetcode 044 —— Wildcard Matching
- leetcode -- Wildcard Matching
- Leetcode:Wildcard Matching
- LeetCode第44题之 Wildcard Matching
- LeetCode: 44. Wildcard Matching
- leetcode 44. Wildcard Matching
- LeetCode44 Wildcard Matching
- leetcode 44. Wildcard Matching
- [Leetcode] Wildcard Matching
- LeetCode之Wildcard Matching
- LeetCode 44. Wildcard Matching