题目
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
.
思路一:遍历
1、对于T中的每一个字符,找到在S中的位置,得到一个二维的数组 vector<vector<int>> myvector
2、找到满足条件 myvector[i][j]<myvector[i+1][k] 的所有排列。
例如 S="abaabcbc" T="abc" 可以得到下列二维数组 myvector
1 3 4
2 5 7
6 8
然后对该数组进行广度优先搜索,可得到满足条件的数目。
class Solution {
public:
int numDistinct(string S, string T) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
int lenS = S.size();
int lenT = T.size();
if(lenS<lenT)
return 0;
vector<vector<int> > myvector(lenT,vector<int>());
for(int i=0;i<lenT;i++)
{
for(int j=i;j<lenS;j++)
if(S[j]==T[i])
myvector[i].push_back(j);
}
return countbigger(myvector, -1, 0);
}
int countbigger(vector<vector<int> > &myvector, int num, int level)
{
if(level==myvector.size()-1)
{
int count=0;
for(int i=0;i<myvector[level].size();i++)
if(myvector[level][i]>num)
count++;
return count;
}
int count=0;
for(int i=0;i<myvector[level].size();i++)
{
if(myvector[level][i]>num)
count += countbigger(myvector, myvector[level][i], level+1);
}
return count;
}
};
时间复杂度是 O(M*N)+...
所以对于 Juge Large 不能通过,只能通过小数据。
思路二:递归
class Solution {
public:
int numDistinct(string S, string T) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
if(S.size()<T.size())
return 0;
int num=0;
match(S,T,0,0,num);
return num;
}
void match(string &S, string &T, int indS, int indT, int &num)
{
if(indS>=S.size() || indT>=T.size())
return ;
if(S[indS]==T[indT])
{
if(indT==T.size()-1)
num++;
else
match(S,T,indS+1,indT+1,num);
}
match(S,T,indS+1,indT,num);
}
};
大数据还是过不了。
思路三:动态规划
用迭代的方法实现动态规划:
class Solution {
public:
int numDistinct(string S, string T) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
int lenS = S.length();
int lenT = T.length();
if(lenS<1 || lenT<1 || lenS<lenT) {
return 0;
}
vector<vector<int>> num(lenT,vector<int>(lenS,0));
if(S[0]==T[0]) num[0][0] = 1;
for(int j=1;j<lenS;j++){
if(S[j]==T[0]){
num[0][j]=num[0][j-1]+1;
} else {
num[0][j]=num[0][j-1];
}
}
for(int i=1;i<lenT;i++){
for(int j=i;j<lenS;j++){
if(T[i]==S[j]){
num[i][j]=num[i-1][j-1];
}
num[i][j]+=num[i][j-1];
}
}
return num[lenT-1][lenS-1];
}
};
此时速度快多了。
T 串中前 i 个字母的子串 在 S 串中前 j 个字母的子串中含有的个数——>这样的问题记为 A[i][j] , 可以得到递推式:
(1)首先 A[i][j] 是由 A[i][j-1] 到这一步的;(而不是由 A[i-1][j] ,这是因为 S 中j-1 个字符含有 T 的前 i 个字符个数,与 S 中前 j 个含有 T 的前 i 个字符是类似问题,有递推关系,需要匹配的子串没有变化;但是 S 中 j 个字符含有的 T 的前i个字符,与S中前 j 个字符含有 T 的前 i-1 个字符 就不是 相似之问题了,它们的解之间没有相关性)
(2)如果 T[i] = S[j] ,则 还有另外一种情况到这一步:由 A[i-1][j-1] 到这一步的;
还有其他的解释:
Let f(i, j)
to be the number of distinct subsequences ofT(j:)
inS(i:)
.
Consider the i
th character in
S
.
If we can use it to match T[j]
, namelyS[i] == T[j]
,
then f(i, j) = f(i+1, j+1)
.
If we do not want use it in our matching,
then f(i, j) = f(i+1, j)
.
Thus, f(i, j) = f(i+1, j) + (S[i] == T[j]) * f(i+1, j+1)
.
/*
Let f(i, j) to be the number of distinct subsequences ofT(j:) in S(i:).
Consider the ith character in S.
If we can use it to match T[j], namelyS[i] == T[j],
then f(i, j) = f(i+1, j+1).
If we do not want use it in our matching,
then f(i, j) = f(i+1, j).
Thus, f(i, j) = f(i+1, j) + (S[i] == T[j]) * f(i+1, j+1).
*/
public class Solution {
private int number = 0;
public int numDistinct(String s, String t) {
if(s == null || t == null){
return 0;
}
if(s.length()<t.length()){
return 0;
}
//matchDistinct(s, t, 0, 0);
int[][] table = new int[s.length()][t.length()];
if(s.charAt(0) == t.charAt(0)){
table[0][0] = 1;
}
for(int i=1; i<s.length(); i++){
if(s.charAt(i) == t.charAt(0)){
table[i][0] = table[i-1][0] +1;
} else {
table[i][0] = table[i-1][0];
}
}
for(int i=1; i<s.length(); i++){
for(int j=1; j<t.length(); j++){
if(s.charAt(i) == t.charAt(j)){
table[i][j] = table[i-1][j] + table[i-1][j-1];
} else {
table[i][j] = table[i-1][j];
}
}
}
return table[s.length()-1][t.length()-1];
//return number;
}
private void matchDistinct(String s, String t, int m, int n){
if(m>=s.length() || n>=s.length()){
return;
}
if(s.charAt(m) == t.charAt(n)){
if(n == t.length()-1){
number ++;
} else {
matchDistinct(s, t, m+1, n+1);
}
}
matchDistinct(s, t, m+1, n);
}
}
优化空间后得到代码:
class Solution {
public:
int numDistinct(string S, string T) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
int lenS = S.length();
int lenT = T.length();
if(lenS<1 || lenT<1 || lenS<lenT) {
return 0;
}
vector<int> num(lenT+1,0);
num[0]=1;
for(int j=0;j<lenS;j++){
for(int i=lenT-1;i>=0;i--){
if(T[i]==S[j]){
num[i+1]+=num[i];
}
}
}
return num[lenT];
}
};