Skip to content

算法训练营 Day 54 | ● 392.判断子序列 ● 115.不同的子序列 #51

Description

@KoEkko

392.判断子序列

dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。

function isSubsequence(s: string, t: string): boolean {
  const dp: number[][] = new Array(s.length + 1)
    .fill(0)
    .map((_) => new Array(t.length + 1).fill(0));
  for (let i = 1; i <= s.length; i++) {
    for (let j = 1; j <= t.length; j++) {
      if (s[i - 1] === t[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = dp[i][j - 1];
      }
    }
  }
  return dp[s.length][t.length] === s.length;
}

115.不同的子序列

求不同的子序列的个数
dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。

确定递推公式
这一类问题,基本是要分析两种情况

s[i - 1] 与 t[j - 1]相等
s[i - 1] 与 t[j - 1] 不相等
当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。

一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dp[i-1][j-1]。

一部分是不用s[i - 1]来匹配,个数为dp[i - 1][j]。
所以当s[i - 1] 与 t[j - 1]相等时,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

首先明确dp数组的含义是以i-1为结尾和以j-1为结尾时, s的子序列中t出现的个数。那么当s【i-1】==t【j-1】的时候,考虑s【i-1】与t【j-1】匹配,此时子序列的长度+1了,但是个数没有变,还是dp【i-1】【j-1】的个数。举个简单的例子:s="bag", t="bag",那么当对比s【1】和t【1】的时候,dp【2】【2】代表的是当s="ba"和t="ba"时s的子序列中t出现的个数,此时的结果与dp【1】【1】即s="b", t="b"的结果是相同的,只是子序列长度从"b"增加到了"ba"

当s[i - 1] 与 t[j - 1]不相等时,dp[i][j]只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]

所以递推公式为:dp[i][j] = dp[i - 1][j];

从递推公式dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 和 dp[i][j] = dp[i - 1][j]; 中可以看出dp[i][j] 是从上方和左上方推导而来,如图:,那么 dp[i][0] 和dp[0][j]是一定要初始化的。

每次当初始化的时候,都要回顾一下dp[i][j]的定义,不要凭感觉初始化。

dp[i][0]表示什么呢?

dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。

那么dp[i][0]一定都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1。

再来看dp[0][j],dp[0][j]:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数。

那么dp[0][j]一定都是0,s如论如何也变成不了t。

最后就要看一个特殊位置了,即:dp[0][0] 应该是多少。

dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串t。

function numDistinct(s: string, t: string): number {
  const dp: number[][] = new Array(s.length + 1)
    .fill(0)
    .map((_) => new Array(t.length + 1).fill(0));
  for (let i = 0; i < s.length; i++) {
    dp[i][0] = 1;
  }
  for (let i = 1; i <= s.length; i++) {
    for (let j = 1; j <= t.length; j++) {
      if (s[i - 1] === t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
      else dp[i][j] = dp[i - 1][j];
    }
  }
  return dp[s.length][t.length];
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions