今天來講第10題

回傳給予的字串 (s) 是否可成功對應 使用了 '.' 和'*' 的正規表達式regular expression 的模板字串 (p):
初始化動態規劃表 (dp table):
(m+1) * (n+1) 的二維陣列 dp[m+1][n+1],其中 m 是字串 s 的長度,n 是模式 p 的長度。dp[i][j] 表示 s[0..i-1] 和 p[0..j-1] 是否匹配。dp[0][0] = true,表示空字串與空模式相匹配。*:如果模式的形式像 a* 或 .*,那麼這可以匹配空字串,因此可以設置 dp[0][j] = dp[0][j-2]。遍歷字串 s 和模式 p:
s,內層遍歷模式 p。遍歷時,對於每個字元 s[i-1] 和模式 p[j-1],需要處理三種匹配情況。處理匹配情況:
情況 1:字元完全匹配或 . 匹配:
s[i-1] == p[j-1],或者 p[j-1] == '.'(可以匹配任意單一字元),則 dp[i][j] = dp[i-1][j-1]。也就是說,當前字元匹配後,取決於之前的匹配情況。情況 2:模式中出現 *:
* 可以匹配前一個字元零次或多次。* 和它前面的字元,對應 dp[i][j] = dp[i][j-2]。s[i-1] == p[j-2](或 p[j-2] == '.'),則可以進一步匹配前一個字元,對應 dp[i][j] = dp[i-1][j]。情況 3:無匹配:
s[i-1] 與模式 p[j-1] 無法匹配,則 dp[i][j] = false。最終結果:
dp[m][n] 即為結果,表示字串 s 和模式 p 是否完全匹配。class Solution {
public:
bool isMatch(string s, string p) {
int m = s.length(), n = p.length();
vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
// 初始化 dp table, 空字串與空模式是匹配的
dp[0][0] = true;
// 處理像 "a*" 這樣的模式,這種情況可以匹配空字串
for (int j = 2; j <= n; j += 2) {
if (p[j - 1] == '*') {
dp[0][j] = dp[0][j - 2];
}
}
// 填充 dp table
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '.' || s[i - 1] == p[j - 1]) {
// 當字元匹配,或當模式為 '.' 時,繼承上一匹配狀態
dp[i][j] = dp[i - 1][j - 1];
} else if (p[j - 1] == '*') {
// '*' 的情況,判斷是否可以讓前一個字元重複 0 次或者多次
dp[i][j] = dp[i][j - 2]; // '*' 代表前一個字元出現 0 次
if (p[j - 2] == '.' || s[i - 1] == p[j - 2]) {
// 前一個字元與當前匹配,可以繼承 dp[i-1][j]
dp[i][j] = dp[i][j] || dp[i - 1][j];
}
}
}
}
return dp[m][n];
}
};