Java实现最长递增子序列O(nlogn)

简介: 最长递增子序列(longest increasing subsequence)LIS问题是指,在一个给定的数值序列中,找到一个子序列(元素在原序列中不一定是连续的,子串是连续的),使得这个子序列元素的数值依次递增,并且这个子序列的长度尽可能大。

时间复杂度O(n^2)的解法

算法思想: 假设要计算序列a[0]…a[n-1],a[n]的LIS,引入辅助数组dp,dp[i]存储以a[i]结尾的LIS。dp[0]=1,即以a[0]结尾的(只有1个数)LIS为1,最优子结构为:dp[i] = max(dp[j]) +1 (a[j]<a[i] && 0<=j<i )

public static int LIS(int[] a){
		int n;
        if (a == null || (n = a.length) == 0)
            return 0;
        int maxlen = 1,clen;
        int[] dp = new int[n];
        dp[0] = 1;
        for (int i = 1;i < n;i++){
            clen = 0;
            for (int j = 0;j < i;j++)
                if (a[j]<a[i] && clen<dp[j])
                    clen = dp[j];
            dp[i] = clen + 1;
            if (maxlen < dp[i])
                maxlen = dp[i];
        }
        return maxlen;
    }

时间复杂度O(nlogn)的解法

算法思想: 在查找dp[i]前面满足a[j]<a[i]的最大dp[j]时,由顺序查找改为二分查找,时间复杂度即可降为O(nlogn)。
另外引入一个数组b,b中的元素满足b[ dp[i] ] = a[i],即当最长递增子序列的长度为dp[i]时子序列的末尾元素为b[ dp[i] ] = a[i](若有多条序列长度相同,取末尾元素最小的),此时数组c的下标表示长度,数组b的值表示该长度(下标)下的递增子序列的末尾元素。可证明数组b是非递减的

public static int LIS(int[] a){
        int n;
        if (a == null || (n = a.length) == 0)
            return 0;
        int maxlen = 1,index;
        int[] b = new int[n+1];
        b[1] = a[0];
        for (int i = 1;i < n;i++){
            if (a[i] > b[maxlen]){
                maxlen++;
                b[maxlen] = a[i];
            }else {
            	//在数组b里找到大于等于a[i]的下标
                index = binarySearch(1, maxlen, b, a[i]);
                b[index] = a[i];
            }
        }
        return maxlen;
    }

    public static int binarySearch(int start, int end, int[] b, int target) {
        int pivot;
        while (start <=end) {
            pivot = (start + end) / 2;
            if (target >= b[pivot])
                start = pivot + 1;
            else
                end = pivot - 1;
        }
        return start;
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

b17a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值