Given a string S and a string T, count the number of distinct subsequences of T in S. 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). Here is an example: S = "rabbbit", T = "rabbit" Return 3.
class Solution { public: void DFS(string S, string T,int si,int num, vector<char> &tp) { if(num == sizeB){ answer ++; return ; } if(si >= sizeA || num > sizeB) return ; for(int i = si; i<sizeA ; i++) { if(S[i] == T[num]) { tp.push_back(S[i]) ; DFS(S,T,i+1, num+1, tp); tp.pop_back() ; } } } int numDistinct(string S, string T) { // Start typing your C/C++ solution below // DO NOT write int main() function sizeA = S.size(); sizeB = T.size(); if(sizeA < sizeB) return 0; answer = 0; int i; for( i=0 ; i< sizeA ; i++) if(S[i] == T[0]) break ; if(i < sizeA) { vector<char> tp; DFS(S,T,i,0,tp) ; } return answer; } private : int answer ; int sizeA; int sizeB; };
上述代码使用DFS来做,大数据还过不了
DP:
将“S串中前m个字母的子串中包含多少个T串中前n个字母的子串”这样的问题记为A[m][n]。 可以得到递推式 :
if(S[m-1] == T[n-1]) A[m][n] = A[m-1][n-1] + A[m-1][n];
else A[m][n] = A[m-1][n-1];
再处理边界情况即可。简单起见,用类似打表记录式的递归实现。
class Solution { public: int Dp(int m, int n, int *tp, const string &S,const string & T ) { if(n == -1) return 1; else if(m == -1) return 0; if(m < n) return 0; if( tp[m*sizeB+n] != -1 ) return tp[m*sizeB+n]; tp[m*sizeB+n] = S[m] == T[n] ? Dp(m-1, n-1,tp, S, T) + Dp(m-1, n,tp,S,T) : Dp(m-1, n,tp,S,T) ; return tp[m*sizeB+n]; } int numDistinct(string S, string T) { // Start typing your C/C++ solution below // DO NOT write int main() function sizeA = S.size(); sizeB = T.size(); int *tp = new int[sizeA * sizeB] ; for(int i = 0; i< sizeA * sizeB ;i++) tp[i] = -1; return Dp(sizeA-1, sizeB-1,tp,S, T) ; } private : int sizeA; int sizeB; };
上面必须先判断n == -1,在判断m == -1. 很重要。
一种写法:
class Solution { public: int numDistinct(string S, string T) { // Note: The Solution object is instantiated only once and is reused by each test case. //if(S == null || T == null) return -1; int lens = S.size(); int lent = T.size(); if(lens == 0 || lent == 0) return 0; vector<vector<int>> m(lent+1,vector<int>(lens+1,0)); for(int j = 0; j <= S.length(); j++) m[0][j] = 1; for(int i = 1; i <= lent; i++) for(int j = i; j <= lens; j++) m[i][j] = T[i-1] != S[j-1] ? m[i][j-1] : m[i-1][j-1] + m[i][j-1]; return m[lent][lens]; } };
节省空间的写法:
class Solution { public: int numDistinct(string S, string T) { // Note: The Solution object is instantiated only once and is reused by each test case. int M = T.length(); //subsequence length int N = S.length(); if (M > N || M ==0 || N==0) { return 0; } vector<int> m(M, 0); m[0] = (T[0] == S[0]?1:0); for (int i=1; i<N; ++i) { for(int j=min(i,M); j>=1;--j) { m[j] = m[j] + ((S[i]==T[j])?m[j-1]:0); } m[0] = m[0] + (S[i]==T[0]?1:0); } return m[M-1]; } };