博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【LeetCode】115. 不同的子序列
阅读量:3567 次
发布时间:2019-05-20

本文共 2512 字,大约阅读时间需要 8 分钟。

在这里插入图片描述

规定 :
(1)S(0, i-1) 表示 S 的前 i 个字符组成的字符串,因此基数为 0,所以最后一个字符即第 i-1 个。

(2)S[i-1] 即表示 S 的第 i-1 个字符。


使用动态规划来处理,则有 dp[i][j] 代表 S(0, i-1)T(0, j-1) 对应的解。

对于 dp[i][j] 有:

  1. S[i-1]T[j-1] 不相等时,则 S 的第 i-1 个字符肯定是要删除的,删除了 S 的第 i-1 个字符,就等价于求 S(0, i-2)T(0, j-1) 的解,因此 dp[i][j] 就等价于 dp[i-1][j]

    也可以反过来想,对于 T(j-1) ,当 S[i-1]T[j-1] 不相等时,对于 S 的前 i-1 个字符(即 S(0, i-2)),再加上第 i-1 个字符,是不会影响到关于 T(j-1) 的结果的。

  2. S[i-1]T[j-1] 相等 时,S 的第 i-1 个字符也是要删除的,但是当其删除时,就会有两种情况:

    抵消T[j-1](即抵消掉 T 的第 j-1 个字符,则剩下 T 的前 (j-1) 个字符,此时最后一个字符变为第 T[j-2] 个了),此时就对应于 dp[i-1][j-1]

    或者不抵消(即 T 的第 j-1 个字符还在,则剩下的依然是 T 的前 j 个字符),此时对应于 dp[i-1][j]

    此时 dp[i][j] 为两种情况的和,即 dp[i][j] = dp[i-1][j-1] + dp[i-1][j]

public int numDistinct(String s, String t) {
if (s == null || s.length() == 0) {
return 0; } if (t == null || t.length() == 0) {
return 1; } int sLen = s.length(); int tLen = t.length(); // 注意数组空间为 [sLen + 1][tLen + 1] int[][] dp = new int[sLen + 1][tLen + 1]; // 初始值赋值 for (int i = 0; i <= sLen; i++) {
dp[i][0] = 1; } // 最终要求得 dp[sLen][tLen] for (int i = 1; i <= sLen; i++) {
for (int j = 1; j <= tLen; j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; } else {
dp[i][j] = dp[i - 1][j]; } } } return dp[sLen][tLen];}

注意,对于 dp[i][0],即 T 的字串长度为 0 的时候,有 dp[i][0] 为 1,即空字符串为 S 的子串只有一种可能,那就是删除 S 的所有字符。

而对于 dp[0][j] 不包括 dp[0][0](因为它属于 dp[i][0] 对应的情形 ),即 S 为空字符串,此时不管 T 多长,都无法通过删除 S 中的字符来变成 T,因此 dp[0][j] 为 0。

上述实现的空间复杂度为 O(sLen*tLen)


空间复杂度还可以优化,即使用一纬的辅助数组,此时重点就是对于 dp[i-1][j-1] 状态的保存,因为它在遍历的时候会被 dp[i][j-1] 给覆盖。

此时,就可以用一个临时变量,来保存被覆盖之前的 dp[i-1][j-1] 状态。

public int numDistinct(String s, String t) {
if (s == null || s.length() == 0) {
return 0; } if (t == null || t.length() == 0) {
return 1; } int sLen = s.length(); int tLen = t.length(); // 使用一纬数组,此时 dp[j] 表示 t 的前 j 个字符 int[] dp = new int[tLen + 1]; dp[0] = 1; for (int i = 1; i <= sLen ; i++) {
int pre = dp[0]; dp[0] = 1; for (int j = 1; j <= tLen; j++) {
// 用临时状态保存更新前的 dp[j],此时为 dp[i-1][j-1] 对应的状态 int tmp = dp[j]; if (s.charAt(i-1) == t.charAt(j-1)) {
dp[j] = pre + tmp; } else {
dp[j] = tmp; } // 将更新前的 dp[i] 赋值给 pre,用于遍历下一个元素 pre = tmp; } } return dp[tLen];}

转载地址:http://drerj.baihongyu.com/

你可能感兴趣的文章
数据库基础技巧及用法
查看>>
实用方法:无request参数时获得当前的request的方法
查看>>
JS操作数组常用实用方法
查看>>
springboot实现CAS的server服务器端的搭建,并实现链接mysql数据库,自定义加密算法
查看>>
Python超详细的安装教程
查看>>
小甲鱼Python第一讲(我和Python的第一次亲密接触)
查看>>
小甲鱼Python第三讲(小插曲之变量和字符串)
查看>>
小甲鱼Python第十一讲(一个打了激素的数组2)
查看>>
小甲鱼Python第十三讲(戴上了枷锁的列表)
查看>>
小甲鱼Python第十四讲(各种奇葩的内置方法)
查看>>
小甲鱼Python第十五讲(格式化)
查看>>
小甲鱼Python第十七讲(Python的乐高积木)
查看>>
小甲鱼Python第十九讲(函数,我的地盘听我的)
查看>>
小甲鱼python第二十讲(内嵌函数和闭包)
查看>>
小甲鱼Python第二十一讲(lambda表达式)
查看>>
小甲鱼Python第二十三讲、第二十四讲(递归-这帮小兔崽子、汉诺塔)
查看>>
小甲鱼Python第二十七讲(集合)
查看>>
可调谐半导体激光器的窄线宽测试及压缩
查看>>
matlab中 %d,%f,%c,%s
查看>>
常见的光纤接头汇总
查看>>