最长上升子序列(LIS)问题求解及标记数组

一、问题求解

1.DP  O(n^2)

比较基础的DP,直接上状态转移方程:

dp [ i ] = max { dp [ j ] + 1 ,dp [ i ] } (1 <= j <  i,a[ j ] < a[ i ]) 

int DP(int a[],int n){
    int ans = 0;
    for(int i=1;i<=n;i++)
        dp[i] = 1;
    for(int i=1; i<=n; i++)
        for(int j=1; j<i; j++)
            if(a[j] < a[i])
                dp[i] = max(dp[i], dp[j]+1);
    for(int i=1; i<=n; i++)
        ans = max(ans, dp[i]);
    return ans;
}

2.贪心+二分  O(nlogn)

对于一个数组,想要求解最长上升子序列,容易想到当序列末尾元素较小时,其后更容易增加较大元素,从而使序列增大。因此,我们仅需维护一个tmp数组(tmp中tmp [ i ]处储存当上升子序列长度为i时,末尾元素的最小值,由此可知tmp数组长度即为最长上升子序列长度),当a [ i ] > tmp[ len ] 时,将 len++,tmp [ len ] = a [ i ],否则使用a [ i ]更新数组tmp,二分查找a [ i ]可插入的位置,即第一个大于等于a [ i ]的tmp[ j ],并用a [ i ] 更新tmp [ j ]。

代码如下:

int LIS(int a[],int n){
    tmp[1] =  a[1];
    int len = 1;
    for(int i = 2; i <= n; i++)
        if(a[i]>tmp[len])
            tmp[++len] = a[i];
        else
            tmp[upper_bound(tmp + 1,tmp + len + 1,a[i])-tmp] = a[i];
    return len;
}

二、标记数组

因为一般acm竞赛一般关注算法复杂度,因此一般都使用第二种复杂度为O(nlogn)的算法,因此我仅用这个算法求标记数组。使用f数组维护a [ i ]位置的数当前的最长上升子序列长度,然后使用ans数组从后往前遍历一遍,k1 = len,当f [ i ] = k1时,若k1==len,直接将i添加到ans[ len ],否则判断a[ i ]小于ans[ len + 1 ]时将i添加到ans[ len ],len--。ans数组中从下标1到len中储存的就是最长上升子序列的下标。

代码如下:

int LIS(int a[],int n){
    tmp[1] =  a[1];
    int len = 1;
    f[1] = 1 ;
    for(int i = 2; i <= n; i++){
        if(a[i]>tmp[len]){
            tmp[++len] = a[i];
            f[i] = len;
        }
        else{
            int m = upper_bound(tmp + 1,tmp + len + 1,a[i])-tmp;
            tmp[m] = a[i];
            f[i] = m;
        }
    }
    int k1 = len;
    int maxx = 0x3f3f3f3f;
    for(int i = n; i > 0; i--){
            if(k1<=0)
                break;
            if(f[i] == k1 && maxx > a[i]){
                ans[k1] = i;
                k1--;
                maxx = a[i];
            }
    }
    return len;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值