要求最长公共上升子序列(LCIS),我们要先学会最长上升子序列(LIS)和最长公共子序列(LCS)。
最长上升子序列
求数列
a
a
a的最长上升子序列
设
f
i
f_i
fi表示前
i
i
i个数的最长上升子序列的长度,则
f
i
=
max
j
<
i
∧
a
[
j
]
<
a
[
i
]
f
j
f_i=\max\limits_{j< i\wedge a[j]<a[i]}f_j
fi=j<i∧a[j]<a[i]maxfj
code
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]>a[j]) f[i]=max(f[i],f[j]+1);
}
}
这个代码是 O ( n 2 ) O(n^2) O(n2)的,用线段树或树状数组可以优化到 O ( n l o g n ) O(nlogn) O(nlogn),但这与我们的主题没有太大关联,所以这里就不再赘述了。
最长公共子序列
求数列
a
a
a和数列
b
b
b的最长公共子序列
设
f
i
,
j
f_{i,j}
fi,j表示数列
a
a
a前
i
i
i个和数列
b
b
b前
j
j
j个的最长公共子序列,则
f
i
,
j
=
m
a
x
(
f
i
,
j
−
1
,
f
i
−
1
,
j
,
f
i
−
1
,
j
−
1
+
(
a
i
=
=
b
j
)
)
f_{i,j}=max(f_{i,j-1},f_{i-1,j},f_{i-1,j-1}+(a_i==b_j))
fi,j=max(fi,j−1,fi−1,j,fi−1,j−1+(ai==bj))
code
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i-1][j],f[i][j-1]);
if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
}
}
时间复杂度也是 O ( n 2 ) O(n^2) O(n2)的
最长公共上升子序列
求最长公共上升子序列就是前两种方法的结合。
设
f
i
,
j
f_{i,j}
fi,j表示数列
a
a
a前
i
i
i个和数列
b
b
b前
j
j
j个的最长公共子序列。当
a
i
=
=
b
j
a_i==b_j
ai==bj时,在
[
i
,
j
−
1
]
[i,j-1]
[i,j−1]中选出最大的
f
i
,
k
f_{i,k}
fi,k并转移
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=[i-1][j];
if(a[i]==b[j]){
int mx=1;
for(int k=1;k<j;k++){
if(a[i]>b[k]) mx=max(mx,f[i-1][k]+1);
}
f[i][j]=max(f[i][j],mx);
}
}
}
时间复杂度为
O
(
n
3
)
O(n^3)
O(n3),很容易时超,所以我们要稍微优化一下
每次求
m
x
mx
mx是在
[
1
,
j
−
1
]
[1,j-1]
[1,j−1]中求最大值,而
j
j
j是从小到大增加的,那么我们可以在
j
j
j增大的时候顺便求出此时
m
x
mx
mx的值,就可以省去一维循环,还能将
f
f
f数组压掉一维。
code
for(int i=1;i<=n;i++){
int mx=1;
for(int j=1;j<=m;j++){
if(a[i]==b[j]){
f[j]=max(f[j],mx);
}
if(a[i]>b[j]){
mx=max(mx,f[j]+1);
}
}
}
本文介绍了如何求解最长公共上升子序列问题,首先讲解了最长上升子序列和最长公共子序列的基本概念及算法实现,并在此基础上融合两者,提出了求解最长公共上升子序列的方法。
1275

被折叠的 条评论
为什么被折叠?



