最长递增子序列

博客围绕给定长度为N的数组,求解最长单调自增子序列问题展开。介绍了三种解法,一是转换为最长公共子序列问题求解,时间复杂度O(n^2);二是动态归纳法(暴力法),时间复杂度O(n^2);三是时间复杂度为O(nlgn)的方法,并给出了具体操作示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4.

参考:https://blog.youkuaiyun.com/u013178472/article/details/54926531

 

解法1 最长公共子序列法 O(n^2)

这个问题可以转换为最长公共子序列问题。如例子中的数组A{5,6, 7, 1, 2, 8},则我们排序该数组得到数组A‘{1, 2, 5, 6, 7, 8},然后找出数组A和A’的最长公共子序列即可。显然这里最长公共子序列为{5, 6, 7, 8},也就是原数组A最长递增子序列。

 

解法2 动态归纳法(暴力法) O(n^2)

设长度为N的数组为{a0,a1, a2, ...an-1),则假定以aj结尾的数组序列的最长递增子序列长度为L(j),则L(j)={ max(L(i))+1, i<j且a[i]<a[j] }。也就是说,我们需要遍历在j之前的所有位置i(从0到j-1),找出满足条件a[i]<a[j]的L(i),求出max(L(i))+1即为L(j)的值。最后,我们遍历所有的L(j)(从0到N-1),找出最大值即为最大递增子序列。时间复杂度为O(N^2)。

 

解法3  O(nlgn)

首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1
然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1
接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2

以此类推

public int lis(int[] array){
	if(null == array || array.length == 0){
		return 0;
	}

	int len = 1;
	int[] len2min = new int[array.length + 1];
	len2min[0] = array[0];
	for(int i = 1; i < array.length; i++){
		if(array[i] > len2min[len - 1]){
			len2min[len] = array[i];
			len++;
		}else{
			//二分查找
			int index = binSearch(len2min, array[i], len);
			len2min[index] = array[i];
		}
	}

	return len;
}

public int binSearch(int[] len2min, int arrayi, int len){
	int left = 0;
	int right = len - 1;
	while(left <= right){
		int mid = left + (right - left) / 2;
		if(arrayi > len2min[mid]){
			left++;
		}else if(arrayi < len2min[mid]){
			right--;
		}else{
			return mid;	
		}
	}

	return left;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值