Java值傳遞和引用傳遞
阿新 • • 發佈:2021-07-12
題目中的匹配是一個「逐步匹配」的過程:我們每次從字串 p 中取出一個字元或者「字元 + 星號」的組合,並在 s 中進行匹配。對於 p 中一個字元而言,它只能在 s 中匹配一個字元,匹配的方法具有唯一性;而對於 p 中字元 + 星號的組合而言,它可以在 s 中匹配任意自然數個字元,並不具有唯一性。因此我們可以考慮使用動態規劃,對匹配的方案進行列舉。
我們用 \(f[i][j]\) 表示 s 的前 \(i\) 個字元與 p 中的前 \(j\) 個字元是否能夠匹配。在進行狀態轉移時,我們考慮 p 的第 \(j\) 個字元的匹配情況:
如果 p 的第 \(j\) 個字元是一個小寫字母,那麼我們必須在 s 中匹配一個相同的小寫字母,即
也就是說,如果 s 的第 \(i\) 個字元與 p 的第 \(j\) 個字元不相同,那麼無法進行匹配;否則我們可以匹配兩個字串的最後一個字元,完整的匹配結果取決於兩個字串前面的部分。
如果 p 的第 \(j\)個字元是 *
,那麼就表示我們可以對 p 的第 \(j-1\) 個字元匹配任意自然數次。在匹配 \(0\) 次的情況下,我們有
也就是我們「浪費」了一個字元 + 星號的組合,沒有匹配任何 s 中的字元。
在匹配 \(1,2,3, \cdots\) 次的情況下,類似地我們有
\[\begin{aligned} & f[i][j] = f[i - 1][j - 2], \quad && \text{if } s[i] = p[j - 1] \\ & f[i][j] = f[i - 2][j - 2], \quad && \text{if } s[i - 1] = s[i] = p[j - 1] \\ & f[i][j] = f[i - 3][j - 2], \quad && \text{if } s[i - 2] = s[i - 1] = s[i] = p[j - 1] \\ & \cdots\cdots & \end{aligned} \]總的轉移方程如下:
如果我們通過這種方法進行轉移,那麼我們就需要列舉這個組合到底匹配了 s 中的幾個字元,會增導致時間複雜度增加。
用\(i - 1\)代替上式的\(i\)得到:
\[f[i-1][j] \ |= \begin{cases} f[i-1][j−2] \\ f[i - 2][j - 2] \And\And s[i-1] = p[j - 1] \\ f[i - 3][j - 2] \And\And s[i - 2] = s[i - 1] = p[j - 1] \\ \cdots\cdots \end{cases} \]於是轉移方程可簡化為:
\[f[i][j] \ |= \begin{cases} f[i][j−2] \\ f[i - 1][j] \And\And s[i] = p[j - 1] \end{cases} \]總的轉移方程如下:
\[f[i][j] |= \begin{cases} f[i - 1][j - 1] \And\And s[i] = p[j] & p[j] \ne '*' \\ f[i][j-2] \ || \ f[i-1][j] \And\And s[i] = p[j-1] & p[j] = '*' \end{cases} \]注意點
第一層迴圈\(i\)下標從\(0\)開始,因為'*'可以匹配\(0\)個元素。
class Solution {
public:
bool isMatch(string s, string p) {
int n = s.size(), m = p.size();
s = ' ' + s, p = ' ' + p;
vector<vector<int>> f(n + 1, vector<int>(m + 1));
f[0][0] = true;
auto match = [&](int i, int j) {
if(i == 0) return false;
return s[i] == p[j] || p[j] == '.';
};
for(int i = 0; i <= n; i++)
for(int j = 1; j <= m; j++)
if(p[j] == '*') {
f[i][j] |= f[i][j - 2];
if(match(i, j - 1))
f[i][j] |= f[i - 1][j];
}
else {
if(match(i, j))
f[i][j] |= f[i - 1][j - 1];
}
return f[n][m];
}
};