描述:
實現.和*號匹配,*表示前面字符0~無窮個,.表示任意一個字符。
要求全部,匹配,不是部分匹配。
解決:
思路類似最長公共子序列,
dp[i][j] = dp[i - 1][j - 1], 如果s[i] == p[j] || p[j] == '.'
dp[i][j - 2], 如果p[j] == '*' && s[i] != p[j - 1]
dp[i - 1][j] || dp[i][j - 1] || dp[i - 1][j - 1] || dp[i - 1][j - 2] || dp[i][j - 2], 如果p[j] == '*' && s[i] == p[j - 1]
稍稍解釋下:
對於s和p,設各個最后一個字符為x, y,p的倒數第二字符為z,除此外前面字符設為S,P,則:
s = Sx
p = Pzy
如果x == y或y == '.',則如果S和Pz匹配,則s和p匹配,因為最后兩字字母是匹配的。這就縮減了問題規模。
而對於y == '*'的情況,需要考慮z:
如果x != z,則只有在s和P匹配的情況下,s和p才匹配。
如果x == z,設匹配符號為~吧,方便,則如果S~P,S~Pz,S~Pzy,Sx~P,Sx~Pz,都可得出s和p匹配。
代碼壓縮了空間,用一些額外變量保存會用到的變量。時間復雜度O(m*n),空間復雜度O(n)。
bool cmatch(char s, char p) { return p == '*' || p == '.' || s == p; } bool isMatch(string s, string p) { int m = s.size(); int n = p.size(); bool* arr = new bool[n + 1](); arr[0] = 1; for (int i = 2; i <= n; ++i) if (p[i - 1] == '*' && arr[i - 2] == true) arr[i] = true; int j2 = arr[0]; int j1 = arr[1]; int sa = arr[2]; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) if (j == 0) { j2 = arr[0]; arr[0] = false; } else if (j == 1) { j1 = arr[1]; arr[1] = i == 1 && cmatch(s[0], p[0]); } else { sa = arr[j]; if (p[j - 1] == '*') arr[j] = cmatch(s[i - 1], p[j - 2]) && (arr[j] || arr[j - 1] || j1 || j2 || arr[j - 2])?true:arr[j - 2]; else arr[j] = cmatch(s[i - 1], p[j - 1])?j1:false; j2 = j1; j1 = sa; } } return arr[n]; }