题目大意
给定母串S和待匹配串T,求T能在母串S中匹配多少次(不一定要连续匹配,并且母串中多个相同字母可以依次使用,但均只能使用一次,如S=rabbbit T=rabbit, 则S中三个连续的b可以依次匹配T中两个bb各一次(),故答案为3。
解题思路
字符串匹配并且要求结果只为一个数字的时候,很多情况都是使用DP,这题也不例外,建立数组dp[i][j]表示按题目要求当前T串前i个字符匹配S串前j个字符的匹配结果。
建立转移方程:
当T[i] != S[j] 时,显然其值不会改变,因此dp[i][j] = dp[i][j-1];
当T[i] == S[j] 时,此时可以考虑从两个方向转移到当前dp[i][j];
第一个方向:dp[i-1][j-1],将T[0...(i-1)]记为T‘ ,表示在T'尾部增加一个当前字符;
第二个方向:dp[i][j-1],将T[0...(i)]记为T‘' ,表示替换掉T’‘尾部的一个字符(必与当前字符相同);
由于整个过程只用从T的前一步状态转移而来,因此使用一个2*n(n为母串S的长度)的二维数组就能实现dp全过程。
总结
重点考虑匹配串T,分析其每扩展一个字符后,可由哪些原来的状态转移到新的当前状态来。这道题目想到了就不是很难,主要是多了一些不必要的判断,不过为了保证程序易读且正确,加上这些判断也是值得的,可以后期逐步求精。
代码
class Solution {
public:
int numDistinct(string S, string T)
{
int n = S.length();
int m = T.length();
if (m > n)return 0;
int dp[2][11000];
bool jud = false;
memset(dp, 0, sizeof(dp));
int index = 0;
for (int i = 0; i < n; i ++){
if (S[i] == T[0]){
if (!jud){
jud = true;
dp[index][i] = 1;
}
else dp[index][i] = dp[index][i-1]+1;
}
else if (i) dp[index][i] = dp[index][i-1];
}
for (int i = 1; i < m; i ++){
jud = false;
index^=1;
for (int j = i; j < n; j ++){
if (T[i] == S[j]){
if (!jud){
jud = true;
dp[index][j] = dp[index^1][j-1];
}
else dp[index][j] = dp[index^1][j-1]+dp[index][j-1];
}
else dp[index][j] = dp[index][j-1];
}
for (int j = 0; j < n; j ++) dp[index^1][j] = 0;
}
return dp[index][n-1];
}
};