最长递增子序列O(N^2),O(N log(N))

来源:互联网 发布:php.ini file uploads 编辑:程序博客网 时间:2024/04/30 05:50

O(N log(N))解法以前见过,忘记了,面试题里发现出现过,复习一下~

问题描述:给出一个长度为n的数字序列,求其中最长的递增的子序列。

子序列可以不连续。


解法1 O(N^2)

维护一个数组dp[],dp[i]表示的是输入数据arr[]中,以arr[i]结尾的最长递增子序列的最大长度

然后枚举终点i,用终点之前的j,并且满足arr[j]<arr[i] &&dp[j]+1>dp[i]时更新dp[i]即可.

#include<stdio.h>int main(){    int n,t;    int arr[1111];    int dp[1111];    scanf("%d",&t);    while(t--){        scanf("%d",&n);        for(int i=1;i<=n;i++){            scanf("%d",&arr[i]);        }        dp[1]=1;        int ans=1;        for(int i=2;i<=n;i++){            dp[i]=1;            for(int j=1;j<i;j++){                if(arr[i]<=arr[j]&&dp[i]<dp[j]+1){                    dp[i]=dp[j]+1;                    if(dp[i]>ans)ans=dp[i];                }            }        }        printf("%d\n",ans);    }}

解法2 O(N log(N))

维护一个数组c,c[i]记录的是"对于当前状态下"长度为i的最长递增子序列的终点的最小数字

开始时只有c[0]=min_INF,其他的c[x]=max_INF 枚举i

i=1; 现在要计算c[1],c[1]被arr[1]更新,因为arr[1]>c[0].

i=2; 我们只需要考虑arr[2]是否大于c[1]和c[0](因为我们目前只有这2个值)

       如果arr[2]>c[1]那么c[2]=arr[2],否则(arr[2]一定大于c[0],因为c[0]=min_INF)看arr[2]是否可以更新c[1]

i=3; 考虑arr[3]是否大于c[2],c[1],c[0],

       如果arr[3]>c[2]那么c[3]=arr[3],否则

       如果arr[3]>c[1]那么c[2]=min(c[2],arr[3])否则c[1]=min(c[1],arr[3])

i=4.....

可以看出每次只需要找到最后一个小于arr[i]的c[x],

而在更新时c数组中新加入的值一定是比之前最大的还要大

而对之前的数进行更新时,也是在最一个最远的位置(之前的数比他小,之后的数比他大)进行更新,也就是说c数组是单调的

所以我们在对于任何一个arr[i]对c进行更新位置查找时,可以二分.

最终最大的非max_INF 的c[x]的x就是结果了。

#include<stdio.h>#include<string.h>int arr[1111],c[1111];int get(int str[],int ed,int key){    int left=0,right=ed,mid;    while(right>=left){        mid=(left+right)/2;        if(c[mid]<=key){            left=mid+1;        }else right=mid-1;    }    return left;}int main(){    int t,INF=0x7F7F7F7F,n;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        for(int i=1;i<=1;i++)scanf("%d",&arr[i]);        memset(c,INF,sizeof(c));        c[0]=-INF;        for(int i=1;i<=n;i++){            int now=get(arr,i-1,arr[i]);            if(arr[i]<c[now])c[now]=arr[i];        }        for(int i=n;i>=1;i--){            if(c[i]!=INF){                printf("%d\n",i);break;            }        }    }}





0 0
原创粉丝点击