實現支援 '.' 和 '*' 的正則表達式匹配:
'.' 匹配任意單一字元'*' 匹配前一個字元零次或多次(含 '.')匹配需覆蓋整個輸入字串(非部分匹配)。
| 輸入字串 (s) | 模式 (p) | 結果 | 解釋 |
|---|---|---|---|
| aa | a | false | 模式只能匹配單一 'a' |
| aa | aa | true | 完全匹配 |
| aaa | aa | false | 字串過長 |
| aa | a* | true | '*' 讓 'a' 重複一次 |
| aa | .* | true | '.*' 可匹配任意字串 |
| ab | .* | true | '.*' 匹配 'ab','.'匹配'a','*'匹配'.'本身(即'b') |
| aab | c*a*b | true | 首個 '*' 讓 'c' 出現 0 次,'a*' 匹配 'aa' |
模式中 '*' 只能出現在字元之後,決策點在於:當遇到 '*' 時,我們有兩種選擇:
isMatch(s, i, p, j):字串 s[i:] 是否匹配模式 p[j:]
public class Solution {
public boolean isMatch(String s, String p) {
return isMatch(s, 0, p, 0);
}
private boolean isMatch(String s, int i, String p, int j) {
int ls = s.length();
int lp = p.length();
// 基礎情況:模式已耗盡
if (j == lp) {
return i == ls; // 字串也必須耗盡才算匹配
}
// 情況 1:模式下一字元不是 '*',或已是最後一字元
// 必須逐字元匹配
if (j == lp - 1 || p.charAt(j + 1) != '*') {
return (i < ls && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'))
&& isMatch(s, i + 1, p, j + 1);
}
// 情況 2:模式下一字元是 '*',複雜決策點
// 嘗試匹配 0 次、1 次、多次...
while (i < ls && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.')) {
// 嘗試跳過「字元+*」(匹配 0 次)
if (isMatch(s, i, p, j + 2)) {
return true;
}
// 匹配 1 次,繼續嘗試更多
i++;
}
// 所有嘗試均失敗,最後嘗試匹配 0 次
return isMatch(s, i, p, j + 2);
}
}
為避免重複計算,可引入 Boolean[][] memo 記憶化,或採用 DP 表格法:
// DP 狀態:dp[i][j] 表示 s[i:] 與 p[j:] 是否匹配
// 初始化:dp[ls][lp] = true
// 狀態轉移參考上述遞歸邏輯
// 時間/空間複雜度均優化至 O(m*n)
這道題是字串匹配與狀態機建模的經典範例,掌握其遞歸結構對解決類似「通配符匹配」、「正則引擎實現」等問題極有幫助。