動態規划
做動態規划很簡單,三步走:
第一步,判斷可否用動態規划做,即判斷是否滿足兩個條件:①最優子結構,②重疊子問題。顯然該題求s與p是否match,可由其字串層層分解上來。
我語文不好一兩句解釋不清楚,不過看完這篇文章,基本就會判斷是不是滿足這兩個條件了。
算法-動態規划 Dynamic Programming--從菜鳥到老鳥
第二步,描述狀態。這個題的狀態還是比較好描述的,boolean f[i][j] :表示子串s[0~i-1] 與子串p[0~j-1]是否match
第三步,找出狀態轉移方程以及初始狀態:
最難的地方就在於如何找狀態轉移方程。
如何找?即分析當前狀態由上層哪個或者哪些以及處理過的狀態轉換而來
假設題中沒有*,那就簡單了,狀態轉移方程為f[i][j] = f[i-1][j-1] && s[i]==p[j]
現在加上,我們就可以按情況討論嘛,如果p[j]!='' ,那么狀態轉移方程就是f[i][j] = f[i-1][j-1] && s[i]p[j]
如果p[j]'' , 即可以代替0個、1個或者多個,對於的狀態f[i][j]可以由f[i-1][j-1],f[i][j-1]和f[i-1][j]而來,即f[i][j] = f[i - 1][j - 1] || f[i - 1][j] || f[i][j - 1];
初始狀態,顯然f[0][0]=true
不過,還有一個初始狀態很容易被遺忘:
當p以開頭時
if (p.length() > 0 && p.charAt(0) == '') {
f[0][1] = true;
}
代碼
class Solution {
public boolean isMatch(String s, String p) {
String tp = "";
//處理p中多余的*
for (int i = 0; i < p.length(); i++) {
if (p.charAt(i) == '*') {
tp += '*';
while (i < p.length() && p.charAt(i) == '*') i++;
}
if (i < p.length()) {
tp += p.charAt(i);
}
}
p = tp;
boolean[][] f = new boolean[s.length() + 1][p.length() + 1];
f[0][0] = true;
// 注意,當p以*開頭時
if (p.length() > 0 && p.charAt(0) == '*') {
f[0][1] = true;
}
for (int i = 1; i <= s.length(); i++) {
for (int j = 1; j <= p.length(); j++) {
if (p.charAt(j - 1) == '*') {
f[i][j] = f[i - 1][j - 1] || f[i - 1][j] || f[i][j - 1];
} else {
f[i][j] = f[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?');
}
}
}
return f[s.length()][p.length()];
}
}