文章目录
题目1 最长递增子序列
-
最长递增⼦序列(LIS)
-
编程实现求解最长递增⼦序列的三种动态规划算法(⼀些细节请参考课件)
1.1 算法1:令 L ( k ) L(k) L(k)表示 s [ 1.. n ] s[1..n] s[1..n]中以 s [ k ] s[k] s[k]结尾的LIS的长度,原问题即求解 max 1 ≤ k ≤ n L ( k ) \max_{1\le k\le n}L(k) max1≤k≤nL(k)
1.2 算法2:令 L ( i , j ) L(i,j) L(i,j)表示 s [ 1.. n ] s[1..n] s[1..n]中每个元素都⼤于 s [ i ] s[i] s[i]的LIS的长度,再令 s [ 0 ] = − ∞ s[0]=-\infty s[0]=−∞,原问题即求
解 L ( 0 , 1 ) L(0,1) L(0,1)1.3 算法3:构建数组 L L L,令 L ( k ) L(k) L(k)表示 s [ 1.. n ] s[1..n] s[1..n]中⻓度为 k k k且末尾元素最⼩的递增⼦序列的末尾元素,原问题即求解 L L L的长度
-
-
上述算法仅仅求出LIS的长度,请对其改进以求出具体的序列。⾸先给出每种改进算法的基本思路,然后给出伪代码,并分析算法的时空复杂度。
算法1
基本思路
1 建立递归关系
1.1 要求解的子问题:令 L ( k ) L(k) L(k)表示 s [ 1.. n ] s[1..n] s[1..n]中以 s k s_k sk结尾的 L I S LIS LIS的具体序列。
1.2 如何基于子问题求解原问题:根据 L ( i ) ( 1 ≤ i ≤ k − 1 ) L(i) (1\le i \le k-1) L(i)(1≤i≤k−1),找到某个下标 i i i,这个下标的值 s i s_i si小于 s k s_k sk 且这个下标对应的具体序列 L ( i ) L(i) L(i)的长度最长。
1.3 基本情况:原始算法中当 k = 1 k=1 k=1时, L ( k ) = 1 L(k)=1 L(k)=1。改进算法中同样认定 k = 1 k=1 k=1时 L ( k ) = 1 L(k)=1 L(k)=1且具体序列中只有 s 1 s_1 s1
1.4 递归情况:记原始算法中 L I S LIS LIS长度为 L e n ( k ) Len(k) Len(k),本改进算法中具体序列为 L ( k ) L(k) L(k)。根据原始算法中的递归关系,找到使得原始算法中递归关系 L e n ( k ) = max { 1 , max 1 ≤ i ≤ k − 1 { L e n ( i ) + 1 ∣ s k > s i } } Len(k)=\max\{1,\max_{1\le i \le k-1}\{Len(i)+1|s_k>s_i\}\} Len(k)=max{ 1,max1≤i≤k−1{ Len(i)+1∣sk>si}}中满足 s k > s i s_k>s_i sk>si的对应下标 i i i。若 L e n ( k ) = 1 Len(k)=1 Len(k)=1,则认为:以 s k s_k sk结尾的 L I S LIS LIS的具体序列有且只有 s k s_k sk一项,即 L ( k ) = [ s k ] L(k)=[s_k] L(k)=[sk]。若 L e n ( k ) ≠ 1 Len(k)\ne 1 Len(k)=1 ,根据 max 1 ≤ i ≤ k − 1 { L e n ( i ) + 1 ∣ s > s i } } \max_{1\le i \le k-1}\{Len(i)+1|s_>s_i\}\} max1≤i≤k−1{ Len(i)+1∣s>si}}的计算情况,可找到以 s k s_k sk为结尾的具体序列中的序列前一项 s i s_i si,即: L ( k ) = [ L ( i ) , s k ] L(k)=[L(i),s_k] L(k)=[L(i),sk]
2 自底向上求解
2.1 备忘录形式:开辟一个新的数组 L a s t [ 1.. n ] Last[1..n] Last[1..n], L a s t k Last_k Lastk表示使得 L e n ( k ) = max { 1 , max 1 ≤ i ≤ k − 1 { L e n ( i ) + 1 ∣ s k > s i } } Len(k)=\max\{1,\max_{1\le i \le k-1}\{Len(i)+1|s_k>s_i\}\} Len(k)=max{ 1,max1≤i≤k−1{ Len(i)+1∣sk>si}}中满足 s k > s i s_k>s_i