最长上升子序列

主演思想:
遍历之前的所有数并继承他前面的上升长度最长的并且比他小那个数的序列长度,并加一
代码:

# include <cstdio>
# include <iostream>
# include <cstring>
# define MAX 1000
using namespace std;
int s[MAX + 10];//s数组保存序列
int slen [MAX + 10];// 保存以i为终点的最长上升子序列的长度
int n, ml = 0;
int main ()
{
    cin >> n;
    memset (slen , 1, sizeof (slen)); //本身那个数也包含进去
    for (int i=0; i<n; ++i)
        cin >> s[i];

    for (int i=0; i<n; ++i)
    {
        int m = 0;
        for (int j=0; j<i; ++j)
        {
            if (s[j] < s[i] && slen[i] > m)
            m = slen[j]; //m 存放i之前的最长子序列的长度,并不包括i
        }
        slen[i] = m + 1;//讲i自身加上
        if (slen[i] > ml)
            ml = slen[i];//ml是目前为止最长子序列的长度
    }
    cout << ml << endl;

    return 0;
}

另一种解法动态规划, 摘自挑战程序设计竞赛

int n;
int a[MAX], dp[MAX];
void solve ()
{
    int res = 0;
    for (int i=0; i<n; ++i)
    {
        dp[i] = 1;
        for (int j=0; i<i; ++j)
            if (a[i] > a[j])
            dp[i] = max (dp[i], dp[j] + 1);
        res = max (res, dp[i]);
    }
    printf ("%d\n", res);
}

首先dp数列中除了inf之外全是单调递增的,所以可以知道对于每个a最多只需要一次更新。对于这次更新究竟在什么位置,不必逐个遍历, 可以用二分搜索,这样就可以在O(nlogn)时间内求出结果。

int dp[MAX];
void solve ()
{
    fill (dp, dp+n, INF);
    for (int =0; i<n; ++i)
    {
        *lower_bound (dp, dp+n,a[i]) = a[i];
    }
    printf ("%d\n", lower_bound (dp, dp+n, INF)-fp);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值