This is similar to the regular expression matching, but the data is relatively strong.
We also use dp (I, j) to indicate whether s [0... I-1] and P [0... J-1] Match
The basic situation is similar, but it is simpler:
1. DP (0, 0) = true
2. DP (0, j) = dp (0, J-1) & P [J-1] = '*'
3. DP (I, 0) = false
Generally, dp (I, j ):
1. DP (I-1, J-1) & (s [I-1] = P [J-1] | P [J-1] = '? ')
2. DP (I, J-1) & P [J-1] = '*'
3. DP (I-1, j) & P [J-1] = '*'
Since row I only uses the data of the row I-1, the space can be compressed to one dimension. We use a bool currow to indicate the row number of the current access ,! Currow indicates I-1 rows
First version
bool isMatch(const char *s, const char *p) { int m = strlen(s); int n = strlen(p); bool curR = 0; vector<vector<bool>> dp(2); dp[curR] = (vector<bool>(n+1)); dp[!curR] = (vector<bool>(n+1)); dp[0][0] = true; for (int i = 1; i <= n; i++) dp[0][i] = (p[i-1] == '*' && dp[0][i-1]); const char* tmp = p; int cnt = 0; while (*tmp != '\0') if (*(tmp++) != '*') cnt++; if (cnt > m) return false; for (int i = 1; i <= m; i++) { curR = !curR; dp[curR][0]=false; for (int j = 1; j <= n; j++) { dp[curR][j] = (dp[!curR][j-1] && (s[i-1] == p[j-1] || p[j-1] == '?') || dp[curR][j-1] && p[j-1] == '*' || dp[!curR][j] && p[j-1] == '*'); } } return dp[curR][n]; }
Note that there is a pruning, if (CNT> m) return false, used to quickly exclude nonconformities. If there is no such paragraph, it will be TLE.
Version 2
bool isMatch(const char *s, const char *p) { int m = strlen(s); int n = strlen(p); if (!quickElimination(s,p)) return false; bool curR = 0; vector<vector<bool>> dp(2); dp[curR] = (vector<bool>(n+1)); dp[!curR] = (vector<bool>(n+1)); dp[0][0] = true; for (int i = 1; i <= n; i++) dp[0][i] = (p[i-1] == '*' && dp[0][i-1]); for (int i = 1; i <= m; i++) { curR = !curR; dp[curR][0]=false; for (int j = 1; j <= n; j++) { if (p[j-1] == '*') dp[curR][j] = dp[curR][j-1] || dp[!curR][j]; else if (s[i-1] == p[j-1] || p[j-1] == '?') dp[curR][j] = dp[!curR][j-1]; else dp[curR][j] = false; } } return dp[curR][n]; } bool quickElimination(const char *s, const char *p) { int cnt = 0; while (*p != '\0') if (*(p++) != '*') cnt++; if (cnt > strlen(s)) return false; return true; }
The main difference is that when we compute dp (I, j), we use if-else to replace a series of logical operators, increasing the speed by about 30%. When the first version is used for computing, when a statement fails, it calculates the next condition connected with |, resulting in more operations.
Complexity: O (slen * Plen)
Direct Matching Method
In.
bool isMatch(const char *s, const char *p) { // Start typing your C/C++ solution below // DO NOT write int main() function const char* star=NULL; const char* ss=s; while (*s){ if ((*p=='?')||(*p==*s)){s++;p++;continue;} if (*p=='*'){star=p++; ss=s;continue;} if (star){ p = star+1; s=++ss;continue;} return false; } while (*p=='*'){p++;} return !*p; }
The main idea is:
1. * s = * P or * P =? : Match, s ++ P ++.
2. P = '*': it is also a match, but there may be 0 or more characters for matching. Therefore, save the location of '*' (STAR ), and save the location of S (SS ).
3. If it does not match, check whether '*' exists before '*'. If no value exists, false is returned. If yes, the next position of the SS is re-matched with the position after start.
The brute force law is complex with O (slen * slen ).
In this example, Plen and slen are not much different, And the brute force law can find unmatched strings during the search process to terminate the search. DP must traverse all sub-problems before providing solutions, so the second method is much faster.
On OJ, the violent law took 116 Ms, while DP took 720 Ms.
Wildcard matching [leetcode] direct match and DP