关注下方公众号,分享硬核知识
作者 | 小K
出品 | 公众号:小K算法 (ID:xiaok365)
01
故事起源
LIS:Longest Increasing Subsequence(最长递增子序列)。
给你一个整数数组,如何求出其中最长的严格递增子序列的长度?
比如下面绿色和蓝色都是符合要求的子序列,但蓝色的子序列更长,所以最大长度为4。
02
思考
要求最长子序列的长度,那肯定要先找出这个最长的子序列。比如下面蓝色的子序列就是我们要找的序列。
所以整个数组的元素就可以分为两类,一类是属于最终的目标序列,一类是不属于最终的目标序列。
那我们要怎么确定一个元素是否应该选取到目标序列呢?咱们还是从小规模开始分析吧,懂的都懂(小K式思维法)。
03
小规模分析
3.1
一个元素
如果只有一个元素,那自然是要选了,最大长度为1。
3.2
两个元素
如果再加第2个元素,满足递增子序列,两个都选,最大长度为2。
如果再加第2个元素是这样的,选了第1个就选不了第2个,不选第1个就可以选第2个。但怎么选都只能选1个,最大长度是1。
3.3
三个元素
如果选取了前面2个元素,再加第3个元素,已经无法再选取,最大长度为2。
如果前面只选取第1个元素,再加第3个元素,可以选取第3个元素,最大长度也为2。
请问你发现什么规律了吗?
因为是递增序列,所以一个元素能不能选,跟之前选择的最后一个元素有关。如果大于最后一个元素就可以选择,如果小于或等于就无法选择。
04
抽象分析
如果不考虑任何规律,每个元素可以选或不选, 个元素就有 种选取方法。当然要保证递增序列,就可以排除很多不合理的情况,但规模依然很大。
假设原问题已经找到了最大的子序列,现在我再给你加一个元素进来,选还是不选呢?
如果原问题最大长度为X,那选择最新的元素的前提就是最大长度能变成X+1,如果选了长度没变甚至更小那肯定就不选。说明新的元素一定要能接在之前的最优解后面才可选取。
数据规模每扩大一次,最优解也是在之前的最优解上面扩充。
再根据第3小节的分析,对于每一个最优解,其实我们并不关注前面的X-1个元素是怎么选择的,只关注第X个元素是选的啥,那就可以从小规模开始枚举,求出以每个元素作为结尾时的最大长度,这样就可以递推出更大规模的最优解,这其实就是动态规划的思想。
05
动态规划
设
表示以第
个元素为结尾,能得到的最大的长度,那么
一定是从之前的某个最优解递推过来。
即。
代码实现
void dp() {
int a[100], f[100], ans = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
f[i] = 1;
for (int j = 0; j < i; ++j) {
if (a[j] < a[i]) {
f[i] = max