09|子序列问题:详解重要的一大类动态规划问题

我们曾在上一课中提到,有两类重要的动态规划问题需要掌握,其中一个是子数组问题,另一个是子序列问题。今天,我们将深入讲解动态规划中的另一个经典问题,即子序列问题。

相较于子数组问题而言,子序列问题要更复杂一些,这是由子序列的特性决定的。不过有一点比较类似,那就是我们仍然需要小心定义备忘录结构和其对应值的含义。

你应该注意到了,我们把子数组问题和子序列问题放在一块儿讲,这意味着它们之间是有联系的。因此,在开始今天的课程前,我提出这样一个问题:子数组和子序列问题在求解时有什么异同呢

接下来就让我们带着这个问题,开始今天的学习之旅吧。

什么是子序列问题?

类似的,我们要明确一下什么是动态规划中的子序列问题。首先,相较于子数组问题而言,子序列问题要更复杂一些。这是因为,子数组问题是连续的,而子序列问题是不连续的。比如说字符串 “I wanna keep a giraffe in my backyard” 的一种子序列就可以是 “Igbackd”。

因此,你可以看到,子序列不再要求答案是一个连续的串。即便用穷举的思路求解问题,我们都不一定知道该从何下手解决。特别的,当涉及到两个数组或字符串作为输入的情况时,如果没有处理经验,真的不容易想到解法。

其次,一个字符串的子序列,是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。举个例子,“ace” 是 “abcde” 的子序列,但是 “aec” 就不是 “abcde” 的子序列。

再次,如果一个问题涉及以下特征,那么它大概率需要使用动态规划来进行求解:

1. 题目涉及子序列;

2. 问题符合动归典型特征,特别是求“最”优解问题(最大值和最小值);

3. 题目的答案是题设数组的子序列,或者来源于子序列。

其实,一旦技术面试问题涉及子序列,你都几乎不需要考虑动态规划以外的解法了。为什么这么说呢?你考虑一下,一个数组或字符串子序列的组合数肯定是指数级别的,如果想依赖纯粹的穷举来进行求解,从时间复杂度上看,几乎没有求解的可能性。

所以啊,我们虽然说动态规划中的子序列问题是经典动归问题,但它不同于 0-1 背包这种经典问题,事实上它并不好解决。不过我们都学到这了,你应该坚信再难的动归问题都应该有模板可以应对。

没错,今天就让我们用两个经典的案例,来找出解决子序列问题的思路。

最长回文子序列

如果问题含有最长子序列这样的提法,那么它一定是动态规划问题。现在,先让我们一起来看一看最长“回文”子序列问题的描述。

问题:给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000。

示例1:

输入:"asssasms"
输出:5
解释:一个可能的最长回文子序列为 "sssss",另一种可能的答案是 "asssa"。
示例2:

输入:"abba"
输出:4
解释:有三个子序列满足题设要求:"aa"、"bb" 和 "abba",因此答案为 4。

算法问题分析

还记得在解决回文子串时给出的那个简单例子么?我们当时有提到过 “子数组问题的特征是答案也必须是连续的”。显然,子序列问题的特征发生了变化,它的答案可以是连续的,也可以是不连续的。

我现在输入的字符串是 “abca”,那么 “aca” 是原问题的答案吗?在子数组问题中不是;但现在,“aca” 是原问题的答案了。

在前面曾提到过涉及子序列的问题基本上全部都是动态规划问题。那么这个问题符合动态规划问题的特征吗?我们来看一下:

1. 重叠子问题:在穷举的过程中肯定存在重复计算的问题。这是因为各种排列组合间肯定存在重叠子问题的情况;<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值