题目
Given a string S and a string T, count the number of distinct subsequences of S which equals T.
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).
Example 1:
Input: S = "rabbbit", T = "rabbit"
Output: 3
Explanation:
As shown below, there are 3 ways you can generate “rabbit” from S.
(The caret symbol ^ means the chosen letters)
rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^
Example 2:
Input: S = "babgbag", T = "bag"
Output: 5
Explanation:
As shown below, there are 5 ways you can generate “bag” from S.
(The caret symbol ^ means the chosen letters)
babgbag
^^ ^
babgbag
^^ ^
babgbag
^ ^^
babgbag
^ ^^
babgbag
^^^
思路
回溯法
我的第一想法是回溯法,当前能匹配字符匹配或者不匹配,子集树类型
class Solution {
public:
int numDistinct(string s, string t) {
int res = 0;
if(t.length() == 0)return 0;
backtrack(res,s,t,0,0);
return res;
}
void backtrack(int &res, string s, string t, int s_index, int t_index){
//满足某个条件,回溯结束
if(t_index >= t.length()){
res ++;
return;
}
//不满足继续回溯
while(t_index < t.length() && s_index < s.length() && s[s_index] != t[t_index])s_index ++;
if(s_index < s.length()&& s[s_index] == t[t_index] && s.length() - s_index >= t.length() - t.length()){
backtrack(res,s,t,s_index + 1,t_index + 1);
//恢复现场,这里是不匹配当前字符
backtrack(res,s,t,s_index + 1, t_index);
}
return;
}
};
显示为Memory Limit Exceeded,当数据规模较大时问题不能解决
在中间进行剪枝处理后没有解决这个问题
动态规划
这时就考虑到了动态规划,状态res[i][j]表示 S前i + 1位的不同子序列中有几个和T的前j + 1位相同
更新公式
res[i][j] += res[i - 1]res[j]
if(s[i]正好匹配t[j])那么res[i][j] += res[i - 1][j - 1]
具体代码如下:
class Solution {
public:
int numDistinct(string s, string t) {
int sn = s.length();
int tn = t.length();
if(tn == 0)return 1;
if(sn == 0)return 0;
vector<vector<int>>res(sn,vector<int>(tn,0));
if(s[0] == t[0])res[0][0] = 1;
// res[0][0] = s[0] == tn[0] ? 1 : 0;
for(int i = 1; i < sn; i ++){
res[i][0]+=res[i - 1][0];
if(s[i] == t[0])res[i][0] ++;
}
for(int j = 1; j < tn; j ++){
for(int i = j; i < sn; i ++){
res[i][j] += res[i - 1][j];
if(s[i] == t[j])res[i][j] =res[i - 1][j - 1] + res[i][j];
}
}
return res[sn - 1][tn - 1];
}
};
测试没有问题,但是提交又有问题了
这里显示的是在第18行运算时整型int型溢出了
int型: 在32/64位系统中都是32位,范围为-2147483648+2147483647,无符号情况下表示为04294967295。
这里运算的结果为2 666 274 961超了,但是还在无符号整型范围内
因此把题目中的状态数组改为无符号整型
class Solution {
public:
int numDistinct(string s, string t) {
int sn = s.length();
int tn = t.length();
if(tn == 0)return 1;
if(sn == 0)return 0;
vector<vector<unsigned int>>res(sn,vector<unsigned int>(tn,0));
if(s[0] == t[0])res[0][0] = 1;
// res[0][0] = s[0] == tn[0] ? 1 : 0;
for(int i = 1; i < sn; i ++){
res[i][0]+=res[i - 1][0];
if(s[i] == t[0])res[i][0] ++;
}
for(int j = 1; j < tn; j ++){
for(int i = j; i < sn; i ++){
res[i][j] += res[i - 1][j];
if(s[i] == t[j])res[i][j] =res[i - 1][j - 1] + res[i][j];
}
}
return res[sn - 1][tn - 1];
}
};
通过