問題分析:可以用類似於最長公共子串的思路。問b在a中出現的次數,考慮最後乙個字元b[n-1]和a[m-1]
case1:如果b[n-1] = a[m-1],則考慮b[0,...,n-2]在a[0,...,m-2]出現多少次
case2:如果b[n-1] != a[m-1],則考慮b[0,...,n-1]在a[0,...,m-2]出現多少次
子問題:原問題:問b[0,...,n-1]在a[0,..,m-1]中出現的次數
現在變成b[0,...,n-2]在a[0,...,m-2]出現的次數和b[0,...,n-1]在a[0,...,m-2]出現的次數
設f[i][j]表示b的前j個字元b[0,...,j-1]在a的前i個字元a[0,...,i-1]出現的次數
則f[i][j] = f[i-1][j-1](b[j-1] = a[i-1]) + f[i-1][j]
case1 + case2
初始情況;
f[i][0] = 1,(i = 0,...,m)空串在字串裡出現的次數為1,
f[0][j] = 0,(j = 1,...,n)表示字串在空串裡出現的次數是0
計算順序:
f[0][0]...f[0][n]..
.f[m][0]...f[m][n]
答案:f[m][n]
時間複雜度o(mn),空間複雜度o(mn),同樣可以優化到o(n)
**及注釋如下:
def distinct_subs(a,b):
m ,n= len(a),len(b)
if m < n:
return 0
f = [[0 for i in range(n+1)] for j in range(m+1)]
#初始化
for i in range(m+1):
for j in range(n+1):
#f[i][0] = 1,(i = 0,...,m)
#f[0][j] = 0,(j = 1,...,n)
if j == 0:
f[i][j] = 1
continue
if i ==0 :
f[i][j] = 0
continue
#f[i][j] = f[i-1][j-1](b[j-1] = a[i-1]) + f[i-1][j]
f[i][j] = f[i-1][j]
if b[j-1] == a[i-1]:
f[i][j] += f[i-1][j-1]
return f[m][n]
a = ['r','a','b','b','b','i','t']
b = ['r','a','b','i','t']
print(distinct_subs(a,b))
#答案:3
DP之序列 子串問題
dp之序列 字串問題是非常常見的一種問題,它包括下面這些題型 最大連續子串行和 最長不下降子串行 lis 最大公共子串行 最長回文子串 這類問題的最大特點就是它的dp陣列的索引i是依據序列或字串的下標的。即根據序列seq i 或者字串s i 來定義dp i 的含義,例如lis的dp i 的定義就是以...
dp基礎之博弈型取石子
問題分析 要求面對n個石子,是否先手必勝 需要知道面對n 1和n 2個石子,是否先手必勝 子問題 設f i 表示面對i個石子,是否先手必勝 f i true false f i true f i 1 false and f i 2 false 拿一顆石子或兩顆石子都輸 true f i 1 fals...
DP入門之《LIS 最長不降子串行》
剛學dp沒思路,就去找書看,剛開始了解了記憶化搜尋與遞推,對dp問題漸漸開始有了一些理解,並有了一些自己的想法,對書上描述的狀態轉移方程開始感覺有點意思了。今天又看看了對lis的解決方案的描述,感覺貌似明白了,就試著寫了寫,只寫了20行的 就解決問題了,當然,這段 只能給出最優值,而不能給出最優方案...