求一个数组的最长递增子序列(即不一定连续)

求一个数组的最长递增子序列(即不一定连续)

package suanfa.impover;

import java.util.Arrays;

/**
 * 求一个数组的最长递增子序列(即不一定连续)
 */
public class LengthgestSubSequence {

    /**
     *用一个数组,count[i]:表示到第i位为止,最长的递增子序列的长度
     * O(N2)
     */
    public static int concrete(int [] a){
        int [] count =new int [a.length];
        for (int i=0;i<a.length;i++){
            count[i]=1;
            for (int j=i-1;j>-1;j--){
                if (a[i]>a[j]&&count[j]+1>count[i]){
                    count[i]=count[j]+1;
                }
            }
        }
        return count[a.length-1];
    }

    /**
     * 用一个变量来保存第i为之前的递增子序列的最大长度,来减少比较的次数
     *  O(N2)
     */
    public static int concrete2(int [] a){
        int maxL=0;
        int [] count=new int[a.length];
        for (int i=0;i<a.length;i++){
            count[i]=1;
            for (int j=i-1;j>-1;j--){
                if (a[i]>a[j]&&count[j]+1>count[i]){
                    count[i]=count[j]+1;
                }
                if (count[i]>maxL){
                    maxL=count[i];
                    break;
                }
            }
        }

        return maxL;
    }

    /**
     * 前面的方法在计算第i位时,不考虑前面i-1位的数。
     * 现在考虑前i-1位的数:
     *  用maxV[i]记录连续长度为i的序列中的最大值,当第 i+1个数的大于 最长序列中的最大值时,
     *      则把该数并在该序列后面。
     *
     * 具体理解理解程序!!
     * 此时时间复杂度任然为O(n2)
     */
    static  int fun1(int [] a){
        int maxLen=1;
        int [] maxV=new int[a.length+1];
        maxV[0]=Integer.MIN_VALUE;
        maxV[1]=a[0];

        for (int i=1;i<a.length;i++){
            int len=1;
            //  寻找i前面的最长序列
            int j=maxLen;
            for (;j>-1;j--){
                if (a[i]>maxV[j]){
                    len=j+1;
                    break;
                }
            }

            if (len >maxLen){
                maxLen=len;
                maxV[len]=a[i];
            }else if (a[i]>maxV[j] && a[i]<maxV[j+1]){
                maxV[j+1]=a[i];
            }
        }

        return maxLen;
    }

    /**
     * 将上面寻找 i 前最长序列的 过程换成 二分查找:即找小于a[i]的最大maxV[j]
     *
     * 理解:i<j 时, a[i] 也必定小于 a[j]
     *
     * 时间复杂度:O(n*log2n)
     *
     */
    static int  fun2(int [] a){
        int [] maxV = new int[a.length+1];
        maxV[0]=Integer.MIN_VALUE;
        maxV[1]=a[0];
        int maxLen=1;

        for (int i=1;i<a.length;i++){
            int len=1;
            int key=a[i];

            // 寻找i前的最长序列
            int low=0,high=maxLen;
            int mid=0;
            while (low < high-1){
                mid = low + (high-low)/2;
                if (key > maxV[mid]){
                    low = mid +1;
                }else {
                    high = mid-1;
                }
            }
            if (key>maxV[high]){
                mid=high;
                len=high+1;
            }else if (key>maxV[low]){
                mid=low;
                len=low+1;
            }

            if (len>maxLen){
                maxLen=len;
                maxV[len]=a[i];
            }else if (a[i] > maxV[mid] && a[i]<maxV[mid+1]){
                maxV[mid+1]=a[i];
            }
        }

        return maxLen;
    }

    public static void main(String[] args) {
        int [] a1={1,-1,2,-2,3,-3,4};
        int [] a2={1,8,9,10,2,3,4,5,6,7};
        System.out.println(Arrays.toString(a1));
        System.out.println("max length is :"+fun2(a1));
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值