一、题目描述
给你两个字符串
s
和t
,统计并返回在s
的 子序列 中t
出现的个数,结果需要对 109 + 7 取模。示例 1:
输入:s = "rabbbit", t = "rabbit"输出: 3
解释: 如下所示, 有 3 种可以从 s 中得到"rabbit" 的方案。
rabbbit rabbbit rabbbit
示例 2:
输入:s = "babgbag", t = "bag"输出: 5
解释: 如下所示, 有 5 种可以从 s 中得到 "bag" 的方案。babgbag babgbag babgbag babgbag babgbag
提示:
1 <= s.length, t.length <= 1000
s
和t
由英文字母组成
二、解题思路
本题属于动态规划类型的。
1、状态表示
dp[i][j] 表示:在字符串 s 的 [0, j] 区间内的所有子序列中,有多少个 t 字符串中[0, i] 区间的这个子串。
2、状态转移方程
分两种情况来讨论:
- 子序列包含s[ j ](即以s[ j ]结尾):若s[ j ] = t[ i ],则dp[i][j] = dp[i - 1][j - 1] ;
- 子序列不包含s[ j ]:dp[i][j] = dp[i][j - 1] ;(子序列包含s[ j ],但s[ j ] != t[ i ]的情况也是此方程)
所以,最终状态转移方程为dp[i][j] = dp[i][j - 1],如果有s[ j ] = t[ i ]情况,dp[i][j] += dp[i - 1][j - 1]
3、初始化
为了简化初始化,我们可以给dp表增加一行、一列(注意下标映射关系)。
因为s 的子序列中一定有一个空串,所以 t 为空串时,即dp表的第一行,都应初始化为1;
4、填表顺序
「从上往下」填每一行,每一行「从左往右」。
5、返回值
根据「状态表示」,返回 dp[m][n] 的值。
三、代码
class Solution {public int numDistinct(String s, String t) {int m = t.length();int n = s.length();//创建dp表int[][] dp = new int[m+1][n+1];//初始化for(int j = 0; j <= n; j++) {dp[0][j] = 1;}//填表for(int i = 1; i <= m; i++) {for(int j = 1; j <= n; j++) {dp[i][j] = dp[i][j-1];//注意下标映射关系,因为dp表增加了一行一列if(s.charAt(j-1) == t.charAt(i-1)) {dp[i][j] += dp[i-1][j-1];}}}return dp[m][n];}
}