题目大意
给定母串S和待匹配串T,求T能在母串S中匹配多少次(不一定要连续匹配,并且母串中多个相同字母可以依次使用,但均只能使用一次,如S=rabbbit T=rabbit, 则S中三个连续的b可以依次匹配T中两个bb各一次())
解题思路
字符串匹配并且要求结果只为一个数字的时候,很多情况都是使用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]; } };
时间: 2024-11-03 23:20:44