1. 程式人生 > >動態規劃——Distinct Subsequences

動態規劃——Distinct Subsequences

題目大意:給定字串S和T,現在從S中任選字元組成T,要求輸出方案個數。 Example 1:
Input: S = "rabbbit", T = "rabbit"
Output: 3
Explanation: As shown below, there are 3 ways you can generate "rabbit" from S.
(The caret symbol ^ means the chosen letters) rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^
Example 2:
Input: S = "babgbag", T = "bag"
Output: 5
Explanation: As shown below, there are 5 ways you can generate "bag" from S.
(The caret symbol ^ means the chosen letters) babgbag
^^ ^
babgbag
^^    ^
babgbag
^    ^^
babgbag
  ^  ^^
babgbag
    ^^^ 這個題的狀態就是原問題的子問題:從S[0..i]中選取字元組成T[0..j]的方案數,有時候越做越有感覺:既然是動態規劃問題,求解過程中的狀態肯定是原問題的子問題(或者說大多數情況下是這樣的)。主要問題在於這個狀態轉移方程,我拿其中一個狀態出來說,在陣列下標都不越界的情況下,比如說我現在求dp[i][j],方案數包括上一個位置的匹配情況dp[i-1][j-1]乘以(S[i] == T[j])這個布林的判斷值和當次匹配的前一個情況dp[i-1][j],舉個例子來說,T[0..1]為“ba”,則dp[i][0]的方案數一定包括S[0..i-1]匹配T[0]=b時的方案數dp[i-1][0]乘以(S[i] == T[0])這個布林的判斷值和S[0..i-1]匹配T[0..1]="ba"時的方案數dp[i-1][1],加後面那項的原因是dp[i][j]肯定是要包括所有匹配了T[j]的方案數量,這個遞推關係是2包括1,3包括2,4包括3...這樣的包含關係,所以dp[i][j]只需要再加上一個dp[i-1][j]即可。而前面那個乘以布林值的原因是如果之前匹配到T[j-1]的話前面那個乘積值dp[i-1][j-1]*(S[i] == T[j])可以不加相當於加0,只為了少個if判斷,但是後面的dp[i-1][j]還是要加上的。   當然要注意邊界條件,我在leetCode上跑程式的時候出現了輸入串長度為0的情況導致了陣列越界問題。  
 1
public int numDistinct(String s, String t) { 2 int slen = s.length(); 3 int tlen = t.length(); 4 if(slen==0||tlen==0)return 0; 5 if(s.equals(t))return 1; 6 int[][]dp = new int [slen][tlen]; 7 for(int i = 0;i<slen;i++) 8 for(int
j = 0;j<tlen;j++) 9 dp[i][j] = 0; 10 int temp = 0; 11 char t0 = t.charAt(0); 12 for(int i = 0;i<slen;i++) { 13 if(s.charAt(i)==t0) { 14 temp++; 15 dp[i][0] = temp; 16 }else{ 17 if(i>0)dp[i][0] = dp[i-1][0];
18 else dp[i][0] = 0; 19 } 20 } 21 22 for(int i = 1;i<tlen;i++) { 23 for(int j = i;j<slen;j++) { 24 temp = (s.charAt(j)==t.charAt(i))?1:0; 25 dp[j][i] = dp[j-1][i]+dp[j-1][i-1]*temp; 26 } 27 } 28 return dp[slen-1][tlen-1]; 29 }