最长单调序列O(nlbn)

本文介绍了一种求解数组中最长单调子序列(包括严格单调递增、严格单调递减、非严格单调非降及非严格单调非增)的算法实现,通过动态规划结合二分查找的方法,在O(n log n)的时间复杂度内找到指定区间内的最长子序列长度。

 

 

http://blog.sina.com.cn/s/blog_4e4148700100cxjm.html

const int MAX=2000000;
int a[MAX];
//求a【ll...rr】的最长严格单调递增序列长度O(nlbn)
int bb[MAX];
int lcs(int *a,int ll,int rr)
{
    int i,k=1;
    bb[1]=a[ll];
    for(i=ll+1;i<=rr;i++)
    {
        if(a[i]>bb[k]) bb[++k]=a[i];
        else
        {           
            int ll=1,rr=k,mid;
            while(ll<rr)
            {
                mid=(ll+rr)>>1;
                if(bb[mid]>=a[i]) rr=mid;
                else ll=mid+1;
            }bb[rr]=a[i];
        }
    } return k;
}

const int MAX=2000000;
int a[MAX];
//求a【ll...rr】的最长严格单调递减序列长度O(nlbn)
int bb[MAX];
int lcs(int *a,int ll,int rr)
{
    int i,k=1;
    bb[1]=a[ll];
    for(i=ll+1;i<=rr;i++)
    {
        if(a[i]<bb[k]) bb[++k]=a[i];
        else
        {         
            int ll=1,rr=k,mid;
            while(ll<rr)
            {
                mid=(ll+rr)>>1;
                if(bb[mid]<=a[i]) rr=mid;
                else ll=mid+1;
            }bb[rr]=a[i];
        }
    } return k;
}

const int MAX=2000000;
int a[MAX];
//求a【ll...rr】的最长单调非降序列长度O(nlbn)
int bb[MAX];
int lcs(int *a,int ll,int rr)
{
    int i,k=1;
    bb[1]=a[ll];
    for(i=ll+1;i<=rr;i++)
    {
        if(a[i]>=bb[k]) bb[++k]=a[i];
        else
        {           
            int ll=1,rr=k,mid;
            while(ll<rr)
            {
                mid=(ll+rr)>>1;
                if(bb[mid]>a[i]) rr=mid;
                else ll=mid+1;
            }bb[rr]=a[i];
        }
    } return k;
}

const int MAX=2000000;
int a[MAX];
//求a【ll...rr】的最长单调非增序列长度O(nlbn)
int bb[MAX];
int lcs(int *a,int ll,int rr)
{
    int i,k=1;
    bb[1]=a[ll];
    for(i=ll+1;i<=rr;i++)
    {
        if(a[i]<=bb[k]) bb[++k]=a[i];
        else
        {
            int ll=1,rr=k,mid;
            while(ll<rr)
            {
                mid=(ll+rr)>>1;
                if(bb[mid]<a[i]) rr=mid;
                else ll=mid+1;
            }bb[rr]=a[i];
        }      
    } return k;
}

求解序列最长单调序列通常分为最长单调递增子序列最长单调递减子序列,以下是相关算法介绍: ### 最长单调递增子序列 可以把该问题看作一个简单的动态规划(DP)问题。假设`result[k]`代表以第`k`个元素作为结尾的某一个单调序列的长度,那么对于第`k + 1`个元素结尾的单调序列,有`result[k+1]=max(1 + result[i])`,其中`array[i]<array[k + 1]`,`i`的范围是从`0`到`k` [^2]。 以下是Python代码示例: ```python def search(arr): result = [] max_num = 1 for i in range(len(arr)): num_now, val_now = 1, arr[i] for j in range(i): num, val = result[j] if val_now > val: num_now = max(num_now, num + 1) result.append((num_now, val_now)) max_num = max(max_num, num_now) return max_num ``` 以下是C++代码示例: ```cpp #include<iostream> using namespace std; #define NUM 100 int a[NUM]; //序列L int LIS_n2(int n) { int b[NUM] = { 0 }; //辅助数组b int i, j; b[1] = 1; //以a[1]结尾的子序列中只包含一个元素 int max = 0; //数组b的最大值 for (i = 2; i <= n; i++) { int k = 0; for (j = 1; j < i; j++) //0~i-1之间,b的最大值 { if (a[j] <= a[i] && k < b[j]) k = b[j]; } b[i] = k + 1; if (max < b[i]) max = b[i]; } return max; } ``` ### 最长单调递减子序列 有辅助数组`B`后,递推式子为`B[i] = max{B[k] + 1, A[k]>A[i]&&0<=k<i}`,`B[0] = 1`。最长递减序列的长度为`max { B[i], 0<=i<n }`。若要获取这个序列,是一个逆过程。如果知道`B[k]`最大,那么`A[k]`就是最长递减序列的末尾元素。可以搜寻`B[k]`前面的元素(从后往前搜寻),当满足`B[i] + 1 == B[k] && A[i] > A[k]`时,`A[i]`就是前一个元素,递归求解即可。该算法的时间复杂度为$O(n^2)$ [^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值