袁家伟

导航

最长上升子序列&&最长不下降子序列

本文将用二种方法来求各种子序列,但详细介绍求最长上升子序列,其他子序列思路相同,代码也几乎不变。

求最长上升子序列

方法1:

思路:用f[i]来表示序列从 起点 开始到 i 点,最长上升子序列的长度;

所以f[i]初始化为1,因为当前面没有比他小的点时,子序列只有 i点一个点。

当从头开始遍历到 i点,如果在中间碰到比 i点 小的点 (假设为j点),就进行状态转移方程:

f[i] = max(f[i],f[j]+1);

此状态转移方程的意思,我的理解,就是比较将i点放入 j点代表的最长上升子序列长度+1和原本自身的f[i]进行相比,取最大值;

用 {8 4 2 5 3 9 }这个数组进行演示说明(下标从1开始);

//8 4 2 5 3 9 
//最开始 i= 1; 
//f[1]  = 1;
//a[1] = 8;
//由于8之前没有比他小的数,f[1]保持不变
//i =2;
//f[2] =1;
//a[2] =4;
//由于在4之前没有比他小的点,f[2]保持1不变
//i =3;
//f[3] = 1;
//a[3] =2;
//由于在2之前没有比他小的点,f[3]保持不变
//i = 4;
//f[4] = 1;
//a[4] =5;
//5之前比他小的点有 2 ,由于f[2] =1;则f[4] = max(f[3]+1,f[4]) = 2;
//i = 5;
//f[5]  =1;
//a[5] =3;
//3之前比他小的点有2,由于f[2] = 1;则f[5] =max(f[3]+1,f[5]) = 2;
//i = 6;
//f[6] = 1;
//a[6] =9;
//9之前比他小的点有8,4,2,5,3,从8开始,由于f[1] =1 ,则 f[6] =max(f[1]+1,f[6]) = 2;
//                             到4,由于f[2] = 1,则   f[6] =max(f[2]+1,f[6]) = 2;
//                             到2,由于f[3] = 1,则   f[6] =max(f[3]+1,f[6]) = 2;
//                                到5,由于f[4] = 2,则   f[6] =max(f[4]+1,f[6]) = 3;这一步就是在说明f[j] +1 不一定就是最终结果 
//                              到3,由于f[5] = 2,则   f[6] =max(f[5]+1,f[6]) = 3;

代码如下:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005],f[100005];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    int ans = 0;
    for(int i=1;i<=n;i++)
    {
        f[i] =1;
        for(int j=1;j<i;j++)
        {
            if(a[i]>a[j])
            {
                f[i] = max(f[i],f[j]+1);
            }
            ans = max(f[i],ans);
        }
    }
    cout<<ans<<endl;
}

 

方法2:

思路:这次的f[i]数组不再储存每个点的最长子数列,而是长度为i+1的上升子序列中末尾元素的最小值

只将数组遍历一次即可:碰到比f[i] 的数,就放在后面,i++。当碰到比f[i]小的数,就遍历f[]数组,找出第一个比他小的数,并替换掉。

附:介绍一种可以快速查找数组中数大小的办法:

lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。

lower_bound():返回的是被查序列中第一个大于等于查找值的指针

upper_bound():返回的是被查序列中第一个大于查找值得指针

代码如下:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005],f[100005];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    f[1] = a[1];
    int len = 1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>f[len])
        {
            f[++len] = a[i];
        }else{
            int tmp = upper_bound(f+1,f+1+len,a[i]) - f;
            f[tmp] = a[i];
        }
    }
    cout<<len<<endl;
}

 

posted on 2020-02-26 21:26  袁家伟  阅读(263)  评论(0编辑  收藏  举报