leetcode-115. 不同的子序列

题目

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

一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)

示例 1:

输入: S = "rabbbit", T = "rabbit"
输出: 3
解释:

如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案。
(上箭头符号 ^ 表示选取的字母)

rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

示例 2:

输入: S = "babgbag", T = "bag"
输出: 5
解释:

如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案。 
(上箭头符号 ^ 表示选取的字母)

babgbag
^^ ^
babgbag
^^    ^
babgbag
^    ^^
babgbag
  ^  ^^
babgbag
    ^^^

解题思路

动态规划,用dp[n][m]表示字符串S前m位和T前n位的匹配情况。

转移方程:

  1. s[m] != t[n], dp[n][m] = dp[n][m-1], 实际意思是,如果当前2个字符不匹配,那么直接删掉S对应的字符,所以是dp[n][m-1]
  2. s[m] == t[n], dp有2个状态,第一种是保留s[m],则有dp[n-1][m-1]种,第二种是删掉s[m],则有dp[n][m-1]种,两种加起来就是最终的值,即dp[n][m] = dp[n-1][m-1] + dp[n][m-1]

初始化:

  1. dp[0][0] = 1, 含义是"“和”",返回1
  2. dp[x][0] = 0, 含义是如果S为空,T不为空,那么返回0
  3. dp[0][x] = 1, 含义是如果S不空,T为空,可以通过把S全部删除来得到T,所以返回1

初始化只要把dp的第一行改为1即可。

总结

动态规划真的是。。。。只要把状态想清楚了,其实是很简单的

成绩

时间>94.77%
空间>42.86%

代码

class Solution(object):
    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        m, n = len(s), len(t)
        dp = [[0] * (m + 1) for _ in range(1 + n)]
        # init dp
        dp[0] = [1] * (m + 1)
        for row in range(1, n + 1):
            for col in range(1, m + 1):
                if s[col - 1] != t[row - 1]:
                    dp[row][col] = dp[row][col - 1]
                else:
                    dp[row][col] = dp[row - 1][col - 1] + dp[row][col - 1]
        return dp[-1][-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值