leetcode(力扣) 115. 不同的子序列 (动态规划详解)

本文解析了如何利用动态规划解决LeetCode问题392 Distinct Subsequences,讲解了如何定义dp数组、状态转移方程、初始化步骤以及遍历顺序。通过实例说明了当匹配相等字符时如何更新子序列数量。核心在于理解子序列数量与子序列长度的区别,并掌握了二维动态规划的应用。
摘要由CSDN通过智能技术生成

题目在这:https://leetcode-cn.com/problems/distinct-subsequences/

思路分析:

这道题是上一道题 392. 判断子序列 的加强版。

这道题不仅要判断是否是子序列,还要找到所有的情况。

示例 1:
输入:s = “rabbbit”, t = “rabbit”
输出:3
解释:
如下图所示, 有 3 种可以从 s 中得到 “rabbit” 的方案。
rabbbit
rabbbit
rabbbit

1.确定dp数组含义:
dp[i][j] 表示s[i-1] 和t[j-1]的子序列个数。

2.确定状态转移公式

  • 如果s[i-1] == t[j-1]:

    • 则dp[i][j] = dp[i-1][j-1] + dp[i][j-1]
  • 如果s[i-1] != t[j-1]:

    • 则dp[i][j] = dp[i][j-1]

这里解释一下,之前的基础版本里讲过(链接在上面)和本题思路一致,二维数组中某个格子的左上角是, s串的上一个元素和t串的上一个元素相同情况下的子序列数量,某个格子的左边是 当前s串元素和t串的上一个元素子序列的数量。

别混了,这里相等的时候并不是上一题的格子左上角+1。因为上一题要求的是子序列的长度,所以当匹配到俩字符串相等元素的时候要加1 ,而这里的dp含义是子序列的数量,当匹配到相等字符的时候,长度加了,但是子序列的数量并不是+1的改变。

注意:这里所说的上一个元素是指从开头到上一个元素的子序列

例如: s:bagg 和 t:bag ,s[3] 和 t[2]是相同的,但是字符串s也可以不用s[3]来匹配,即用s[0]s[1]s[2]组成的bag。

当然也可以用s[3]来匹配,即:s[0]s[1]s[3]组成的bag。

所以当s[i - 1] 与 t[j - 1]相等时,dp[i][j] = 使用当前的元素匹配 + 不使用当前元素匹配(即dp数组当前格子左边格子记录的数),这里所说的当前元素是指t字符串。

所以:
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

当s[i - 1] 与 t[j - 1]不相等时,dp[i][j]只有一部分组成,不用s[i - 1]来匹配,
(即dp数组当前格子左边格子记录的数)
所以:
dp[i - 1][j]

3.初始化dp数组:

对于第一行,s为空集,空集是任何字符串的子集,所以第一行都是1.
同样第一列的t为空集, 空集仅有空集作为子集。所以除了dp[0][0]=1,第一列都是0.

在这里插入图片描述

4.确定遍历顺序:
应题目要求,即在S串中挑选字母找T。所以我们拿出来T串中的每一个字母去S中遍历。即外层T循环 内层S循环。

完整代码

class Solution:
    def numDistinct(self, s: str, t: str) -> int:
        dp =[[0] * (len(s)+1) for _ in range(len(t)+1)]
        for _ in range(len(s)+1):
            dp[0][_] = 1
        for i in range(1,len(t)+1):
            for j in range(1,len(s)+1):
                if s[j-1] == t[i-1]:
                    # 相等的两种情况
                    dp[i][j] = dp[i-1][j-1] + dp[i][j-1]
                else:
                    dp[i][j] = dp[i][j-1]

        return dp[-1][-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深度不学习!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值