LIS
最长上升子序列,会有各种变种,比如说最长不下降子序列,最长不上升子序列等等,代码差不多,这里以最长上升子序列为例。最长上升子序列,就是在一个序列A中找到一个一个序列中最长的单调递增的子序列(可以不连续)。
LIS有两种解决方法法,
O(n2)
O
(
n
2
)
&
O(nlog2n)
O
(
n
l
o
g
2
n
)
,在这里都给出。
§ § LIS O(n2) O ( n 2 )
朴素的DP,方程可以直接写出:
fi=maxfj+1,其中1≤j≤i,a[j]<a[i]
f
i
=
m
a
x
f
j
+
1
,
其
中
1
≤
j
≤
i
,
a
[
j
]
<
a
[
i
]
Ans=maxelementf
A
n
s
=
m
a
x
e
l
e
m
e
n
t
f
code: c o d e :
int LIS(std::vector< int > &a) {
int ans = 1;
std::vector< int > f(a.size(), 1);
for (unsigned int i = 2; i <= a.size() - 1; i++)
for (unsigned int j = i - 1; j >= 1; j--)
if (a[i] > a[j] && f[i] < f[j] + 1) {
f[i] = f[j] + 1;
if (f[i] > ans)
ans = f[i];
}
return ans;
}
§ § LIS O(nlog2n) O ( n l o g 2 n )
我们对
f
f
数组重新定义,定义为长度为i的上升子序列的最后一个元素(本人在程序中使用了vector,f中所有元素都往前平移一位,所以定义发生改变,但不影响结果),初始化
f[1]=a[1]
f
[
1
]
=
a
[
1
]
,然后每插入一个
a[i]
a
[
i
]
,判断它和
f
f
中最后一个元素的大小,如果大于,就插入,如果不大于的话,就从f中找到第一个大于的,插在后面(可以用upper_bound),
Ans=f.size()
A
n
s
=
f
.
s
i
z
e
(
)
code: c o d e :
int LIS(std::vector< int > &a) {
std::vector< int > f;
f.push_back(a[1]);
for (unsigned int i = 2; i < a.size(); i++)
if (a[i] < f.back())
f[std::upper_bound(f.begin(), f.end(), a[i]) - f.begin()] = a[i];
else f.push_back(a[i]);
return f.size();
}