week10
Week10
Dynamic Programming
question source: Distinct Subsequences
question description
Given a string S and a string T, count the number of distinct subsequences of S which equals T.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, “ACE” is a subsequence of “ABCDE” while “AEC” is not).
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
^^^
這是一道標籤為動態規劃的題。這周講動態規劃的習題課。這類的題目,說簡單不簡單,兩節課才講了6道題,說難也不難,想出來之後才恍然大悟,實現起來也的確很簡單。但關鍵就是怎麼想出來,怎麼分析題目,並用動態規劃的思想去解決。動態規劃是一種非常強大的計算模式,其解決問題的方式是首先定義它的一組子問題,然後按照由小到大,以小問題的解答支援大問題求解的模式,依次解決所有子問題,並最終得到原問題(最大的子問題)的求解。
解決方法
這題是說給出兩個字串S和T,給出S中有多少個子序列與T相等。這跟我們上課所說的編輯距離的經典例題有點像,很自然地,就想到用二維陣列來存放子問題的解。
我們要用一種途徑來縮小原來的問題。
現定義
那麼問題的解就是 f[s.size] [t.size] ;
好了,現在就得思考子問題了,f[i][j]到底可不可以通過f[i - 1][j], f[i][j - 1] 或者f[i - 1][j - 1]得出來呢。
關鍵是要看S[i]和T[j]的關係了。
- 如果S[i] == T[j],那麼有兩種情況,要麼就將這兩個字元匹配,種數就有f[i - 1][j - 1]種,要麼這兩個字元就不匹配,種數就有f[i - 1][j]種,所以總的種數就有f[i - 1][j - 1] + f[i - 1][j]種。
- 如果S[i] != T[i], 那麼這兩個字元就只能不匹配,種數就有f[i - 1][j]種。
最後就要考慮初始情況了。這個二維陣列的某個位置的值依賴於其左上角的值和其上一行的值。那麼得初始化f[i][0]和f[0][j]的值。f[i][0]表示S[0:i]有多少個子序列與空串相同,初始化為1沒毛病。f[0][j]表示S為空串,肯定不存在子序列跟T相同,因此要初始化為0。
r a b b i t
1 0 0 0 0 0 0
r 1
a 1
b 1
b 1
b 1
i 1
t 1
程式碼實現如下。
class Solution {
public:
int numDistinct(string s, string t) {
int s_size = s.size();
int t_size = t.size();
int distinct[s_size + 1][t_size + 1];
for(int i = 0; i <= s_size; i++){
distinct[i][0] = 1;
}
for(int i = 1; i <= t_size; i++){
distinct[0][i] = 0;
}
for(int i = 1; i <= s_size; i++){
for(int j = 1; j <= t_size; j++){
if(s[i - 1] == t[j - 1]){
distinct[i][j] = distinct[i - 1][j - 1] + distinct[i - 1][j];
}else{
distinct[i][j] = distinct[i - 1][j];
}
}
}
return distinct[s_size][t_size];
}
};
關鍵是怎麼想出狀態轉移的關係,想出這個就不難了,我一開始就沒想出怎麼用子問題去解決父問題。耗了很長時間。這個演算法實現效果還是挺好的。我看Discuss裡面還有別的做法,但沒有解釋我就不知道是怎樣的,說明可以有多種動態規劃的做法的。