LintCode : 不同的子序列

这篇博客探讨了如何计算字符串S的不同子序列中字符串T出现的次数。这是一个动态规划问题,通过建立二维数组来存储子问题的解。博主分享了思路,包括状态转移方程,并提供了一个例子,展示了解决此问题的状态矩阵。递归解法虽然未详细展开,但也是解决问题的一种途径。
摘要由CSDN通过智能技术生成

描述

给出字符串S和字符串T,计算S的不同的子序列中T出现的个数。

子序列字符串是原始字符串通过删除一些(或零个)产生的一个新的字符串,并且对剩下的字符的相对位置没有影响。(比如,“ACE”“ABCDE”的子序列字符串,而“AEC”不是)。 

样例

给出S = "rabbbit", T = "rabbit"

返回 3


思路:

动态规划问题,一开始没有想出思路,

看了: http://www.cnblogs.com/yuzhangcmu/p/4196373.html

            https://blog.csdn.net/fightforyourdream/article/details/17346385?reload#comments

这道题可以作为两个字符串DP的典型:

两个字符串:

先创建二维数组存放答案,如解法数量。注意二维数组的长度要比原来字符串长度+1,因为要考虑第一个位置是空字符串。

然后考虑dp[i][j]和dp[i-1][j],dp[i][j-1],dp[i-1][j-1]的关系,如何通过判断S.charAt(i)和T.charAt(j)的是否相等来看看如果移除了最后两个字符,能不能把问题转化到子问题。

最后问题的答案就是dp[S.length()][T.length()]


就以例子来讲,可以画出如下的状态矩阵,如果T[i]==S[j], dp[i][j] = dp[i][j-1] + dp[i-1][j-1] , 否则, dp[i][j] = dp[i][j-1]。

这里的 dp 是以 T.length() 为 行数, 以 S.length() 为 列数的。


代码:
public static int numDistinct(String S, String T) {
        // write your code here
        int[][] dp = new int[T.length()+1][S.length()+1];
        for (int i = 0; i <= S.length(); i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i <= T.length(); i++) {
            dp[i][0] = 0;
        }
        for (int i = 1; i <= T.length(); i++) {
            for (int j = 1; j <= S.length(); j++) {
                dp[i][j] = dp[i][j-1] + (T.charAt(i-1) == S.charAt(j-1)?dp[i-1][j-1]:0);
            }
        }
        for (int i = 0; i <= T.length(); i++) {
            for (int j = 0; j <= S.length(); j++) {
                System.out.print(dp[i][j]+ " ");
            }
            System.out.println();
        }
        return dp[T.length()][S.length()];
    }


递归的解法,没有细看:

  public int numDistinct(String S, String T) {
    // Start typing your Java solution below
    // DO NOT write main() function
    if (S.length() == 0) {
      return T.length() == 0 ? 1 : 0;
    }
    if (T.length() == 0) {
      return 1;
    }
    int cnt = 0;
    for (int i = 0; i < S.length(); i++) {
      if (S.charAt(i) == T.charAt(0)) {
        cnt += numDistinct(S.substring(i + 1), T.substring(1));
      }
    }
    return cnt;
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值