最长上升子序列的两种方法

最长上升子序列

一个序列,比如说a[]={1,7,3,5,9,4,8},找出它的最长上升子序列的个数,很明显是4个,可以是{1,3,5,9},{1,3,5,8}或者{1,3,4,8}。具体怎么实现呢?直观的感受是以1为起点,下一个数比1大,那么上升子序列个数就+1,以1为起点,到7的时候,上升子序列的个数是2;到3的时候也是2,因为3>1&&3<7;再遍历下一个数5,5与1比较大于1,上升子序列的个数为2,再与7比较,5<7,子序列个数不变,再与3比较,5>3,上升子序列的个数+1,为3,以此类推,那么程序的流程大致为:
定义数组b[]用来存放a[]中每个数的上升子序列的个数,找出b[]中最大值。

#include <iostream>
using namespace std;
int main()
{
    int a[] = { 1, 7, 3, 5, 9, 4, 8 };
    int n = sizeof(a) / sizeof(int);
    int b[sizeof(a) / sizeof(int)];
    b[0] = 1;
    for (int i = 1; i < n;i++)
    {
        b[i] = 1;
        for (int j = 0; j < i;j++)
        {
            if (a[i]>a[j] && b[j] + 1>b[i])
                b[i] = b[j] + 1;
        }
    }
    int maxb = 0;
    for (int i = 0; i < n;i++)
    {
        if (maxb < b[i])
            maxb = b[i];
    }
    cout << maxb << endl;
    return 0;
}

上述算法的时间复杂度是O(n^2)

下面这种方法的时间复杂度是O(nlogn)。具体的方法是:采用b[]数组用来存放上升子序列(上面的方法是用来存放当前数的最大上升子序列),还是a[]={1,7,3,5,9,4,8},想要找出最长的子序列,那么每一个值都要尽可能小,比如说{1,3}一定比{1,7}好,那么,在遍历到7的时候,b[]={1,7},这时遍历3,3比7小(3的潜力更大),应该用3代替7,也就是在数组b[]={1,7}中找到3的位置,采用二分法(时间 复杂度O(logn))。具体程序:

#include <iostream>
using namespace std;
int BinSeach(int &item, int *a, int left, int right)
{
    while (left<right)
    {
        int mid = (left + right) / 2;
        if (item > a[mid] && item <= a[mid + 1])
            return mid;
        else if (item < a[mid])
            right = mid - 1;
        else
            left = mid + 1;
    }   
}
int main()
{
    int a[] = { 1, 7, 3, 5, 9, 4, 8 };
    int n = sizeof(a) / sizeof(int);
    int b[sizeof(a) / sizeof(int)];
    b[0] = a[0];
    int len = 1;
    int j = 0;
    for (int i = 1; i < n;i++)
    {
        if (a[i]>b[len - 1])
            j = len++;
        else
            j = BinSeach(a[i], b, 0, len - 1)+1;
        b[j] = a[i];
    }
    cout << len << endl;
    for (int i = 0; i < len;i++)
    {
        cout << b[i] << " ";
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值