您的位置:首页 > 产品设计 > UI/UE

LeetCode | Distinct Subsequences(不同的子序列)

2014-08-14 21:38 295 查看
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
.
题目解析:
S串通过删减元素能形成多少中T串。其相对位置不能改变。

方案一:

通过DFS来求解,当s[i] == t[j]的时候,我们可以选择s[i]深层次递归,也可以不选择s[i]深层次递归。但是会出现超时结果。

class Solution {
public:
int numDistinct(string S, string T) {
CountDistinct(S,0,T,0);
return count;
}
void CountDistinct(string S,int index1,string T,int index2){
if(index2 >= T.size()){
count++;
return;
}
//找到等于T[index2]的点。但在循环中一定要添加变量范围限制
while(index1 < S.size() && S[index1] != T[index2])
index1++;
if(index1 >= S.size())
return;
CountDistinct(S,index1+1,T,index2+1);//选择这个点
CountDistinct(S,index1+1,T,index2);  //不选这个点
}
private:
int count = 0;
};


方案二:

像这种递归超时的情况,可尝试用动态规划来求解。

动态规划难就难在找递推关系上。没有一个正确的方法,就会陷到死角去。

问1:当s[i]和t[j]不相等的时候,t[j]要和s[i]以后的比较。

答:这种思维就错误了,我们用DFS的时候,是上面这种思路,但是动态规划,是将大问题化渐成小问题。因此当s[i]和t[j]不相等的时候,t[j]要和s[i]以后的比较,并且只利用与s[i-1]的比较结果就行了,不需要再往前找。因为当我们求解二维数组的时候,已经求解出了t[j]和s[i-2]等的关系。

如果不好想的话,就那t[m]和s
比较,当两个不相等的时候,就没有s[n+1]了,应该向前找。

问2:递推关系式是什么?

那就考察s[i]和t[j]相等和不相等的情况。

把这个递推条件设为S前i个字符通过删除字符得到T前j个字符的转换方法,用二维数组元素transArr[i][j]记录。

(1)若S[i]==T[j],说明把S[i]、T[j]分别加入S[0~i-1]和T[0~j-1]可以完全复制transArr[i-1][j-1]种转换方式。另外,S[0~i-1]本身(无需加入S[i])也能以transArray[i-1][j]种方式转换为T[0~j]。

transArr[i][j] = transArr[i-1][j-1]+transArr[i-1][j];

(2)若S[i]!=T[j],说明S[i]无法用于转换为T[0~j],T[j]需要从S[0~i-1]中获取,因此S[0~i]与S[0~i-1]无异。

transArr[i][j] = transArr[i-1][j];

有了这两个关系式,才能进行下一步的计算。

问3:边界条件是什么?

递推关系一定要有个其实值,不然求解的时候,就没法向后延伸。我们思考下,当T为空串的时候,S为任意长度,那么删除S所有元素,就能变成T了。也就是边界条件为1。

class Solution {
public:
int numDistinct(string S, string T) {
if(S.size() < T.size() || T.size() == 0)
return 0;

int **arr = new int*[S.size()+1];
for(int i = 0;i <= S.size();i++)
arr[i] = new int[T.size()+1];
for(int i = 0;i <= T.size();i++)
arr[0][i] = 0;
for(int i = 0;i <= S.size();i++)
arr[i][0] = 1;

for(int i = 1;i <= S.size();i++){
for(int j = 1;j <= T.size();j++){
if(S[i-1] == T[j-1])    //数组中和字符串中坐标不一致,应小心
arr[i][j] = arr[i-1][j-1]+arr[i-1][j];
else
arr[i][j] = arr[i-1][j];
}
}

return arr[S.size()][T.size()];
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: