LeetCode115:不同的子序列 [Python3实现]

13 篇文章 0 订阅
2 篇文章 0 订阅

题目

给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
示例 1:
输入: S = “rabbbit”, T = “rabbit”
输出: 3
解释:
如下图所示, 有 3 种可以从 S 中得到 “rabbit” 的方案。
(上箭头符号 ^ 表示选取的字母)
rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

思路

可以借助最长公共子序列的思路,最长公共子序列是找到字符串s1与字符串s2最长的公共部分,而本题可以将公共部分定死,就是T这个串。
首先定义一个二维数组a[lt][ls],其中lt是串T的长度,ls是串S的长度。a[i][j]表示在S[0 ~ j]中,等于T[0 ~ i]的子串共有多少种组合。

分析a[i][j]
  • T[i] != S[j]时, a[i][j]的值就等于a[i][j-1]的值,即a[i][j] = a[i][j - 1],好理解的,因为此时S[0 ~ j]中等于T[0 ~ i]的子串个数,等于S[0 ~ j-1]中等于T[0 ~ i]的子串个数。
  • T[i] == S[j]时,我们要考虑两个值。
    • 第一,a[i][j - 1] 的值,先看下它的意义:S[0 ~ j-1]中等于T[0 ~ i]的子串个数。而我们要求的是S[0 ~ j]中等于T[0 ~ i]的子串个数, 它前面的S[0 ~ j-1]中已经包含了a[i][j-1]T[0 ~ i], 此时再一次T[i] == S[j],倘若把T[i]这个字符换成当前的S[j],不又是a[i][j-1]种吗?所以,此时定有a[i][j] >= a[i][j - 1]
    • 第二,a[i - 1][j - 1]的值,意义是,S[0 ~ j-1]中等于T[0 ~ i-1]的子串个数,哎,也就是s[0 ~ j-1]这个串中, 差一个T[i]就齐了的字串个数,此时刚好S[j] == T[i],把S[j]放到末尾不就齐了吗?
      以上,可以得出 当T[i] == S[j]时,a[i][j] = a[i][j - 1] + a[i - 1][j - 1]

因此,状态方程知道了。

#init 这里初始化a[0][i]
a[0][0] = (S[0] == T[0]) ? 1 : 0;
for i in range(1, ls):
	a[0][i] = a[0][i-1] + 1  if T[0] == S[i]
	a[0][i] = a[0][i-1]  if T[0] != S[i]

for i:
	for j:
	if S[j] != T[i]:
		a[i][j] = a[i][j - 1]
	elif S[j] == T[i]:
		a[i][j] = a[i - 1][j - 1] + a[i - 1][j] 

具体Python代码如下

class Solution:
    def numDistinct(self, s, t):
        if s == '' or t == '':
            return 0
        LS = len(s)
        LT = len(t)
        a = [[0 for _ in range(LS)] for _ in range(LT)]
        if s[0] == t[0]:
            a[0][0] = 1
        for i in range(1, LS):
            if s[i] == t[0]:
                a[0][i] = a[0][i - 1] + 1
            else:
                a[0][i] = a[0][i - 1]
        for i in range(1, LT):
            for j in range(1, LS):
                if s[j] == t[i]:
                    a[i][j] = a[i - 1][j - 1] + a[i][j - 1]
                else:
                    a[i][j] = a[i][j-1]
        return a[LT-1][LS-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值