【算法】最长递增子序列的长度

题目

求一个一维数组a[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6,-7中,最长递增子序列长度为4,可以是1,2,4,6,也可以是-1,2,4,6。

算法思路

算法一(简单暴力)
/**
用b[]记录当前最长递增子序列长度,b[i]表示a[0,...,i]中的最长递增子序列长度;
求b[i],就是从后向前分析,第i个元素的最长递增子序列的长度要么是1(单独成一个序列),要么就是第i-1个元素之前的最长递增子序列加1
**/
public class  LongestIncreasingSubsequence{
   public static void main(String[] args) {
    int a[]={1,-1,2,-3,4,-5,6,-7};//数组
    int len = a.length;//数组长度
    int b[]=new int[len];//b[i]表示a[0,...,i]中的最长递增子序列长度
    for(int i=0;i<len;i++){//初始化为1
        b[i]=1;
    }
    int max=1;//记录最大递增子序列长度
    for(int i=1;i<len;i++){
        for(int j=i-1;j>=0;j--){//寻找i-1前的最长子序列长度
            if(a[i]>a[j]&&b[i]<b[j]+1){//更新最大值,作为i的最长子序列长度
                b[i]=b[j]+1;
            }
        }
        if(max<b[i]){
            max=b[i];
        }
    }

    System.out.println(max);

}
}

时间复杂度为o( n2 )

算法二(快速排序+最长公共子串)

不难理解,对于原数组所求的最长递增子序列,在数组按递增排序之后,也是有序数组的最长递增子序列。
比如a[]={1,-1,2,-3,4,-5,6,-7}
排序之后:a1[]={-7,-5,-3,-1,1,2, 4,6}
则a和a1的最长公共子序列是是1,2,4,6,也可以是-1,2,4,6。而这个也正是a数组的最长递增子序列
所以该算法分为两个步骤,先排序,得到数组a1,之后求两数组公共子序列。
时间复杂度o(nlogn)+o( n2 )=o( n2 )

算法三(二分查找)
/**
maxVal数组是记录最大递增子序列的数组,严格来说,其元素并不是最大递增子序列,但是其元素具有求解最大递增子序列长度的意义。
l是maxVal数组有效长度,也是最终求得最大递增子序列长度
算法估计难以用语言描述,但是可以举个例子:
a[]={1,-1,2,-3,4,-5,6,-7}
i=0,初始化:maxVal={1},l=1;
i=1,a[i]=-1<maxVal[l-1],则查找maxVal数组中是否存在a[i],如果不存在就用a[i]替换maxVal从0到l-1元素中第一个大于a[i]的元素,所以maxVal={-1}
i=2,a[i]=2>maxVal[l-1],则直接将a[i]加入maxVal中即maxVal[l++]=a[i],则maxVal={-1,2},l=2
i=3,a[i]=-3<maxVal[l-1],查找maxVal数组中是否存在a[i],如果不存在就用a[i]替换maxVal从0到l-1元素中第一个大于a[i]的元素,所以maxVal={-3,2}
i=4,a[i]=4>maxVal[l-1],则直接将a[i]加入maxVal中即maxVal[l++]=a[i],则maxVal={-3,2,4},l=3
i=5,a[i]=-5<maxVal[l-1],查找maxVal数组中是否存在a[i],如果不存在就用a[i]替换maxVal从0到l-1元素中第一个大于a[i]的元素,所以maxVal={-5,2,4}
i=6,a[i]=6>maxVal[l-1],则直接将a[i]加入maxVal中即maxVal[l++]=a[i],则maxVal={-5,2,4,6},l=4
i=7,a[i]=-7<maxVal[l-1],查找maxVal数组中是否存在a[i],如果不存在就用a[i]替换maxVal从0到l-1元素中第一个大于a[i]的元素,所以maxVal={-7,2,4,6}
所有过程结束,l就是最长递增子序列的长度为4
上面查找则是用简单的二分查找法,具体代码如下:
**/
public class LongestIncreasingSubsequence {
   public static void main(String[] args) {
       int a[]={1,-1,2,-3,4,-5,6,-7};
       int len = a.length;
       int maxVal[] = new int[len];
       maxVal[0]=a[0];
       int l=1;
       for(int i=1;i<len;i++){
           if(a[i]>maxVal[l-1]){
               maxVal[l++]=a[i];
           }else{
               int pos = binSearch(a,0,l-1,a[i]);
               maxVal[pos]=a[i];
           }
       }
       System.out.println(java.util.Arrays.toString(maxVal));
       System.out.println(l);
    }

    private static int binSearch(int[] a, int left,int right,int x) {
        while(left<=right){
            int mid = (left+right)/2;
             if(a[mid]<=x){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return left;
    }
}

时间复杂度o(nlogn)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值