又是要对两个字符串一顿操作,返回T or F,典型的dp。
1、建立dp矩阵,确定状态变量:dp[i][j]表示the number of distinct subsequences of s[0:i] which equals t[0:j],就是s[0:i]与t[0:j]带入函数所得值,初值都设为0;
2、确定边界:当s为空字符时,如果t不为空字符,那么就不能通过对s里字符进行删减得到与t字符串一样的字符串,所以dp[0][j]应该为0 (对任意j>0)。当t为空字符,当且仅当删除s中全部字符才能得到空字符,所以dp[i][0](对任意i,包括0,因为空字符不做任何处理也是空字符);
3、建立转移方程:当我们考虑dp[i][j]时,可能有两种情况:1)s[i-1]≠t[j-1];2)s[i-1]==t[j-1]。下面我们分情况讨论,可借助下图理解:
1)s[i-1]≠t[j-1]时,要将s[0:i]变成t[0:j],至少要将s[i-1]删除,也就是删除s[k:i] (其中k>0),那么dp[i][j]是不是等于Σdp[k][j]呢?其实dp[i-1][j]已经包括了前面的所有dp[k][j]。回想一下dp矩阵的定义,dp[i-1][j]表示的是s的前i-1个字符能变换得到t的前j个字符的总变换数,那么它就包括了所有k (k>0),s[0:k]变换成t[0:j],再将s[k:i]删除这样的操作。所以dp[i-1][j]就是所有这样的操作数。(真是一顿操作猛如虎啊!)。故dp[i][j]=dp[i-1][j];
2)s[i-1]==t[j-1],这时候可以删除s[i-1],看dp[i-1][j],也可以保留s[i-1],看dp[i-1][j-1]。这时候需注意类似于dp[i-1][j],dp[i-1][j-1]也包括了所有s[0:k]变换成t[0:(j-1)],再将s[k:(i-1)]删除这样的操作。故dp[i][j]=dp[i-1][j]+dp[i][j-1];
4、返回值:应该返回dp[lens][lent]: s[0:lens]变换得到t[0:lent]的变换数。
class Solution(object): def numDistinct(self, s, t): """ :type s: str :type t: str :rtype: int """ if len(s)<len(t): return(0) lens,lent=len(s),len(t) #dp[i][j]: the number of distinct subsequences of s[0:i] which equals t[0:j] dp=[[0 for j in range(lent+1)] for i in range(lens+1)] for i in range(lens+1): dp[i][0]=1 for i in range(1,lens+1): for j in range(1,lent+1): dp[i][j]=dp[i-1][j] if s[i-1]==t[j-1]: dp[i][j]+=dp[i-1][j-1] return(dp[lens][lent])
原文地址:https://www.cnblogs.com/Leisgo/p/11703574.html