题意:

image.png

图示:

image.png

解题思路:

  1. 思路:
  2. 状态定义:dp[i][j]表示:s的前i个字符的子序列中,包含多少个t的前 j 个字符子串
  3. 转移方程:1. s[i-1]==t[j-1]时
  4. 1.1 保留s[i-1],有dp[i-1][j-1]种方法,即:确定s的第i个字符与t的第j个字符对应后,s的前 i-1 个字符有多少种方法变为t的前 j-1 个字符。
  5. 1.2 比如:s = 'rabb' t = 'rab' 保留st中的最后一个b,看前面srab是否可以组成多少个t中的ra,答案是一个
  6. 1.3 不保留s[i-1],有dp[i-1][j]种方法。即:不使用s的第i个字符,s的前 i-1 个字符有多少种方法变为t的前 j 个字符。
  7. 1.4 比如:s = 'rabb' t = 'rab' 不保留s中的最后一个b,我们看s中的rab是否可以组成多少个t中的rab,答案也是一个
  8. 最终,s[i-1]==t[j-1]时,dp[i][j] = dp[i-1][j-1]+dp[i-1][j]
  9. 2. s[i-1] != t[j-1]时,有dp[i-1][j]种方法,即:已知s的第 i 个字符不能与t的第 j 个字符对应,s的前 i-1 个字符有多少种方法变为t的前 j 个字符。
  10. 比如 s = 'ra' t = 'r' s中的a不等于t中的r时,我们看s中除了a前面有几个可以组成t的可能性,即dp[i-1][j]

PHP代码实现:

  1. class Solution {
  2. /**
  3. * @param String $s
  4. * @param String $t
  5. * @return Integer
  6. */
  7. function numDistinct($s, $t) {
  8. $dp = [];
  9. for ($i = 0; $i <= strlen($s); $i++) {
  10. //$t是空字符串的情况,空字符串也是s的子串
  11. $dp[$i][0] = 1;
  12. }
  13. for ($i = 1; $i <= strlen($t); $i++) {
  14. $dp[0][$i] = 0;//s为空,那就没办法匹配了
  15. }
  16. for ($i = 1; $i <= strlen($s); $i++) {
  17. for ($j = 1; $j <= strlen($t); $j++) {
  18. if ($s[$i-1] == $t[$j-1]) {
  19. $dp[$i][$j] = $dp[$i - 1][$j - 1] + $dp[$i - 1][$j];
  20. } else {
  21. $dp[$i][$j] = $dp[$i - 1][$j];
  22. }
  23. }
  24. }
  25. return $dp[strlen($s)][strlen($t)];
  26. }
  27. }

GO代码实现:

  1. func numDistinct(s string, t string) int {
  2. if len(s)==0 || len(s) < len(t) {
  3. return 0
  4. }
  5. dp := make([][]int, len(s)+1)
  6. for i := 0; i <= len(s); i++ {
  7. dp[i] = make([]int, len(s) + 1)
  8. dp[i][0] = 1
  9. }
  10. for i := 1;i <= len(s); i++ {
  11. for j := 1;j <= len(t); j++ {
  12. if s[i-1] == t[j-1] {
  13. dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
  14. } else {
  15. dp[i][j] = dp[i-1][j]
  16. }
  17. }
  18. }
  19. return dp[len(s)][len(t)]
  20. }