• [LeetCode] Distinct Subsequences


    (Version 1.0)

    这题在第一次做的时候走了一些弯路,问题还是出在了对于two sequence DP常用的二维DP的思路切入点不熟。熟悉的话应该很容易开始想到用一个二维数组dp中的元素dp[i][j]表示S.substring(i)中有多少个可以构成T.substring(j)的subsequence。状态转移关系其实是在举了一个例子一步步填表之后看出的规律,然后再从已经得到的规律往回推原因时明白了正确的思路是什么。代码如下:

     1 public class Solution {
     2     public int numDistinct(String S, String T) {
     3         if (S.length() < T.length()) {
     4             return 0;
     5         }
     6         int[][] dp = new int[S.length()][T.length()];
     7         dp[0][0] = S.charAt(0) == T.charAt(0) ? 1 : 0;
     8         for (int i = 1; i < dp.length; i++) {
     9             dp[i][0] = S.charAt(i) == T.charAt(0) ? dp[i - 1][0] + 1 : dp[i - 1][0];
    10         }
    11         for (int i = 1; i < dp.length; i++) {
    12             char c = S.charAt(i);
    13             for (int j = 1; j <= i && j < dp[0].length; j++) {
    14                 dp[i][j] = (c == T.charAt(j)) ? dp[i - 1][j - 1] + dp[i - 1][j] : dp[i - 1][j];
    15             }
    16         }
    17         return dp[dp.length - 1][dp[0].length - 1];
    18     }
    19 }

    对于S.substring(i)的最后一个char S[i],若其与T.substring(j)中的最后一个char不同,说明向S.substring(i - 1)(这里不考虑i为0的情况,因为那是需要初始化dp数组时考虑的情况,且易得)后面append一个S[i]不会造成任何影响,所以在S[i] != T[j]时,dp[i][j] = dp[i - 1][j];但是如果S[i] == T[j],情况就有所不同了:我们可以选择在subsequence里面使用S[i]去match T[j],或者不使用S[i]去match T[j](append了S[i]和不append一样),也就是说维持S.substring(i - 1)的情况不变直接拿来用,所以此时的可能性数量就应该是两种情况的可能性数量之和,dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]。这里第二项取dp[i - 1][j - 1]的原因是,既然确定了S[i]一定要match T[j],那么S.substring(i - 1)就一定只能match到T.substring(j - 1),这样才能把T[j]留给S[i]来match。

    总体看来就是一道非常典型的two sequence DP,状态转移时需要取什么这个还是要花时间练习,正向推理出来正确的情况有点挑战。

  • 相关阅读:
    [知识点]计算几何I——基础知识与多边形面积
    [旧版][知识点]SPFA算法
    [旧版][知识点]A*搜索(启发式搜索)
    [知识点]线段树
    [小工具]ChemistryHelper
    [考试]20150314
    [知识点]Cantor展开
    [旧版][知识点]拓扑排序
    [无效]网络流之Dinic算法
    [SCOI2005]扫雷Mine
  • 原文地址:https://www.cnblogs.com/icecreamdeqinw/p/4328895.html
Copyright © 2020-2023  润新知