最长上升子序列(附路径)

题目描述

给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。

输入格式
第一行包含整数 N。
第二行包含 N 个整数,表示完整序列。

输出格式
输出一个整数,表示最大长度。

数据范围
1 ≤ N ≤ 100000,
−109 ≤ 数列中的数 ≤ 109
输入样例:

7
3 1 2 1 8 5 6

输出样例:

4

法一:线性dp

最长上升子序列(附路径)_第1张图片
代码:

#include
#include

using namespace std;

const int N = 1010;
int n;
int f[N],num[N];

int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>num[i];
    
    for(int i=1;i<=n;i++){//线性dp核心代码
        f[i]=1;//f[i]本身只有一个数的时候就是1
        for(int j=1;j<i;j++){
            if(num[i]>num[j]){
                f[i] = max(f[i],f[j]+1);
            }
        }
    }
    int res=0;
    for(int i=1;i<=n;i++){
        res = max(res,f[i]);
    }
    cout<<res<<endl;
    return 0;
}

法二:二分算法

思想:在数组 i 中记录长度为 i 的上升子序列中最小的值,每次写入一个数就使用二分算法查找更新数组,最后输出数组长度。

#include
#include

using namespace std;

const int N = 100010;
int a[N],q[N];
int n;

int main(){
    cin >> n;
    for(int i = 0; i < n; i ++) cin >> a[i];
    
    int len = 0;
    q[0]=-2e9;
    for(int i = 0; i < n; i ++){
        int l = 0, r = len;//二分模板
        while(l < r){
            int mid = l + r + 1 >> 1;//向上取整
            if(q[mid] < a[i]) l = mid;
            else r = mid - 1;
        }
        len = max(len, r + 1);
        q[r + 1] = a[i];//更新
    }
    cout<<len<<endl;
    return 0;
}

法三:输出路径

可以设置一个数组记录每一次状态转移,之后根据状态转移逆序存储,倒序输出字符。

#include
#include
#include
using namespace std;

const int N = 10010;
char a[N], b[N];//b[N]用于记录路径
int dis[N];//用于记录状态转移
int f[N];

int main(){
    scanf("%s",a + 1);
    int len = strlen(a + 1);
    for(int i = 1; i <= len; i ++){
        f[i] = 1;
        for(int j = 1; j < i; j ++){
            if(a[i] > a[j]){
                f[i] = max(f[i], f[j] + 1);
                dis[i] = j;
            }
        }
    }

    int res = 0;//找到最大值
    for(int i = 1; i <= len; i ++){
        res = max(res, f[i]);
    }
    int index = 0;//找到最大值下标
    for(int i = 1; i <= len; i ++){
        if(f[index] < f[i]){
            index = i;
        }
    }

    int length = len;//逆序存储字符
    for(int i = length; i >= 1; i --){
        b[i] = a[index];
        index = dis[index];
    }
    
    for(int i = 1; i <= length; i ++){
        cout << a[i] << " ";
    }
    cout << res << endl;

    return 0;
}

你可能感兴趣的:(算法,数据结构)