Leecode #115 不同的子序列

1 分钟读完

难度:hard

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

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

题目数据保证答案符合 32 位带符号整数范围。

示例

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

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

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

解题思路

​ 算是很经典的动态规划题了,d[i, j]表示s的前i个字符含有t前j个字符子序列的个数。

当s[i]==t[j]计算两种情况的和:

  • 保持s[i]和t[i]对应,有d[i-1,j-1]个子序列
  • s[i]和t[i]不对应,即在s[i]出现之前,已经有d[i,j-1]个子序列

当s[i]!=t[j]时:

  • d[i,j]=d[i,j-1]

因此可以得到代码

def numDistinct(self, s: str, t: str) -> int:
        s = '_'+s
        t = '_'+t
        l1 = len(s)
        l2 = len(t)
        if l1 < l2:
            return 0

        arr = [[0] * l1 for i in range(l2)]
        for i in range(l1):
            arr[0][i] = 1
        for i in range(1, l2):
            for j in range(i, l1):
                if s[j] == t[i]:
                    arr[i][j] = arr[i][j-1]+arr[i-1][j-1]
                else:
                    arr[i][j] = arr[i][j-1]
        return arr[-1][-1]
# 用时 212ms 内存 28.1mb

然而这道题的经典在于其优化过程,如上代码,我们申请了一个二维的数组,有没有办法减少我们的空间占用呢?我们看到d[i,j]取决于其上一位和左边一位的值,那么我们只用申请一个一维的数组,并用两个变量保存每次迭代时左边和上面的那个数值:

def numDistinct(self, s: str, t: str) -> int:
        s = '_'+s
        t = '_'+t
        l1 = len(s)
        l2 = len(t)
        if l1 < l2:
            return 0
        arr = [1] * l1

        for i in range(1, l2):
            last = 0
            upper = 0
            for j in range(i, l1):
                temp = arr[j]
                if s[j] == t[i]:
                    arr[j] = arr[j-1] + upper
                else:
                    arr[j] = last
                last = arr[j]
                upper = temp
        return arr[-1]
# 用时 112 ms 内存消耗 13.7mb

还有一个更加变态的版本,不过我目前还没搞懂,先贴一下代码

    def numDistinct(self, s: str, t: str) -> int:
        dp = [0]*(len(t)+1)
        dp[0]=1
        for i in range(len(s)):
            for j in range(len(t),0,-1):
                if s[i]==t[j-1]:
                    dp[j] += dp[j-1]
        return dp[-1]
# 用时 88ms 内存消耗 13.7mb

分类:

更新时间: