前置知识
这里是最长上升子序列和最长公共子序列的结合。
我们在定义状态的时候,也可以将二者结合
先把公共子序列找出来,再找最大值
→ f(i,j)表示在a序列的1~i中和b序列的1 ~ j构成的以b[j]结尾的公共子序列长度的最大值。
通常以最末态来做划分,最末态中,b[j]肯定在子序列中,而a[i]不一定,考虑是否可以以a[i]是否在LCIS序列中进行划分。(这里的划分方式同LCS)
lcs划分方式 👇
(1)当a[i]不在序列中,又因为b[j]一定在序列中,所以a[i]≠b[j],此情况下,等同于在a序列的前i-1的数中与b中的前j个数,且以b[j]结尾的LCIS ,即f(i-1,j)
(2)a[i]=b[j]时,为了使前面的数尽可能多的匹配,所以a[i]一定和b[j]配,找到了公共子序列,求最长,参考LIS的处理方式。
因为最后一位都是b[j],寻找倒数第二位,从0 ~ j-1 进行枚举→ k ,需要满足条件bk <bj
LIS的划分情况👇
即
综上,问题得以解决
代码实现为:
这是O(n3)
如何优化至O(n2)
一般情况下优化的方式是看某一维是否可以用其他维度表示出来。
我们发现j不同,k不用,探求一下j与k之间有什么样的关系吗?
j=1 k=0 b[k]<b[j]
j=2 k=0、1 b[k]<b[j]
j=3 k=0、1、2 b[k]<b[j]
即j每增加1,k中就会产生一个新的候选集合,但是因为必须要满足b[k]<b[j],如果b[j]非常小,候选集中的出入情况就会有变化。无法确定k与j之间的关系
但是我们发现,有k进行讨论的前提是a[i]==b[j],可以把条件转化为
b[k]<a[i] 这样a[i]在当前阶段中是一个定值,每次当j增大时,要么会有1个数进入候选集合中,要么没有。
举例
a[i]=5
b={0,2,4,6,2}
j=1 k=0
j=2 k=0,1
j=3 k=0,1,2
j=4 k=0,1,2(因为b[4]=6>a[i],不符合条件)
j=5 k=0,1,2,4
👉 发现每次最多有一个数进入候选集合中,且这个数是j-1
有了这个发现,则不用再遍历k了,每次只需要判断j-1是否要进入候选集合中即可。
即设s为候选集合,当j+1得到j+1时,此时的候选集合情况为:
如果b[j]>a[i] (此时a[i]==b[j+1]) 这个数不满足条件,无法进入候选集合中
如果b[j]<a[i]=b[j+1],j 进入候选结合中,当前的候选集为原来的s(i,j)并 {j}
代码实现👇