最短写法指思路二的第一种写法
问题描述:
给定一个序列X[0···n],找出它的最长的单调递增子序列(Longest Increasing Subsequence)
思路一:
用d[i] 表示以第i个数字为结尾的最长单调递增序列的长度,然后使用
d[i] = max(1, max(d[j] + 1: 1< j< i, a[i]>a[j])) 这个递推关系式计算,用反证法证明正确性,假设所有j < i, a[i] > a[j]的d[j]中,最大下标为max , .同时d[i] > d[max] + 1, 那么将d[i]对应的序列中去掉a[i], 得到的也是递增序列,令最后下标为max2, 那么d[max2] > d[max], 与max为最大递增序列矛盾,得证. 答案就是max(d[j]: j<=n), 时间复杂度为O(n^2)
对应代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
int LIS(vector<int> &a, int n)
{
vector<int> f(n);
for(int i = 0; i < n; i++){
f[i] = 1;
for(int j = 0; j < i; j++){
if(a[j] < a[i] && f[j] + 1 > f[i]){
f[i] = f[j] + 1;
}
}
}
int max = 1;
for(int i = 0; i < n; i++){
if(f[i] > max){
max = f[i];
}
}
return max;
}
int main(){
int n;
vector<int> a(100011);
while(cin >> n){
for(int i = 0; i < n; i++) cin >> a[i];
cout << LIS(a, n) << endl;
}
return 0;
}
思路二:
用f[i]表示当前取得长度为i的最长递增序列的时候,该递增序列最后面的数最小的值。比如序列1 2 4 5 3,f[1]=1,f[2]=2,f[3]=3,f[4]=5. 所以f的长度就是结果。同时该题可以有两种写法,一种是std::set的方法, 一种是二分。时间复杂度为O(nlgn)
代码 std::set
int LIS(vector<int> &a, int n)
{
set<int> f;
set<int>::iterator iter;
int count = 0;
for(int i = 0; i < n; i++){
iter = f.lower_bound(a[i]);
if(iter!= f.end()) {
f.erase(iter);
}
f.insert(a[i]);
}
return f.size();
}
代码 二分
int llower_bound(int f[], int n, int key){
int l = 0;
int r = n - 1;
while(l < r){
int m = (l + r) >> 1;
if(f[m] < key){
l = m + 1;
} else {
r = m;
}
}
return l;
}
int LIS(int* a, int n){
int count = 0;
for(int i = 0; i < n; i++){
if(count == 0 || a[i] > f[count-1]){
f[count] = a[i];
count++;
}else{
f[llower_bound(f,count,a[i])] = a[i];
}
}
return count; // f.size()
}