最长上升公共子序列(Longest Increasing Common Subsequence,LICS)也是经典DP问题,是LCS与LIS的混合。
Problem
求数列 a[1..n], b[1..m]的LICS的长度, a[], b[]数组的元素均为正整数。
Solution
考虑如何定义DP状态,定义DP状态就是定义所谓的最优子问题(optimal subproblem),而DP状态要能转移,就是所谓最优子问题要具有重叠子结构。
将DP状态定义为
DP[i][j]:a[1..i], b[1..j]的以b[j]结尾的LICS的长度
状态转移方程为
DP[i][j] = DP[i-1][j], a[i] != b[j]
= max{DP[i][k] : k<j, b[k] < b[j]} + 1, a[i] == b[j]
---------------------------------------------------------------------
上面的转移方程,时间复杂度为O(N^3), 空间复杂度为O(N^2),都不能接受,必须优化。
先考虑时间优化,不难发现无法O(1)转移的是a[i]==b[j]的情况,我们考虑在转移的同时维护的这种情况所需要的那个最大值。
我们将转移过程写成两循环
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
dp[i][j]..
i在外层循环,内层循环时i不变。
我们将第二种情况下的转移方程该成 DP[i][j] = max{DP[i][k] : k<j, b[k]<a[i]} + 1, a[i] == b[j]
优化的方法就显而易见了,在每层内循环内维护 max{ DP[i][k] : k<j, b[k]<a[i] }。
for(i=1; i<=n; i++)
for(j=1, ma=0; j<=m; j++)
if(b[j]==a[i])
dp[i][j]=ma+1;
else{
dp[i][j]=dp[i-1][j];
if(a[i]>b[j])
ma=max(ma, dp[i][j]);
}
这样时间上就优化到O(N^2)
-----------------------------------------------------------------------
再考虑空间优化,根据转移方程不难看出可用滚动数组
for(i=1; i<=n; i++)
for(j=1, ma=0; j<=m; j++)
if(a[i]==b[j])
dp[j]=ma+1;
else if(a[i]>b[j])
ma=max(dp[j], ma);
空间优化到O(N)
---------------------------------------------------------------------------
不难看出DP的一切优化都建立在正确的转移方程之上,所以对于DP问题,写转移方程是最关键的一步。
LICS的O(N^2)的复杂度还是偏高的,不知这是否理论复杂度。