LIS

最长上升子序列问题

两种复杂度 O(n^2) 和  O(nlogn) 

思想很简单,以每一个元素为结尾,  内层循环判断大小,

用cnt(i) 表示以下标i的元素为结尾的最大上升值,【0,i】区间内,已经求得最优解,典型的动归思想,利用局部最优求整体最优。

cnt(i) = max( cnt(j)+1,cnt(i) );  

先附上较慢的算法O(n^2):

int LIS(vector<int> vec) {	
	int ans = 1;
	for (int i = 1; i < n; i++) {
		int t;
		for (int j = 0; j < i; j++) {
			if (a[j] < a[i]) {
				if (vec[j] + 1 > vec[i])
					vec[i] = vec[j] + 1;
			}
			t = vec[i];
		}
		if (t > ans)
			ans = t;
	}
	return ans;
}

int main()
{
	int t;
	cin >> t;
	while (t--) {
		cin >> n;
		_for(i, 0, n)
			cin >> a[i];
		vector<int> vec(n + 1, 1);
		int ans = LIS(vec);
		cout << ans << endl;

	}
//	system("pause");
	return 0;
}

这个算法的主要在于内层循环浪费时间。

 

 

优化在于使用二分,让内层变成logn 的复杂度,可以模拟一个栈。

思想:  用top代表栈顶,也代表此时的最大长度,所以top初始为1。ans[i] = j;  表示长度为i时的结尾为j。

int arr = {5,7,3,6,10,9} 这样一个序列

ans[1] = arr[1] 硬性条件  ans = {5}

arr[2] = 7,     7 > 5    ans[++top] = 7   ans = {5,7}

arr[3] =3,    3 < 7    这时需要调整,  找到ans序列中第一个大于等于arr[3]的值  将其替换  ans = {3,7}

以此类推,遍历完arr.         top的值就是最大长度。

可以用STL的lower_bound() 函数寻找其第一个大于等于位置。

int main()
{
	int T, p, i, j, k, d;
	cin >> T;
	while (T--) {
		cin >> p >> d;
		for (i = 1; i <= p; ++i)
			cin >> arr[i];

		ans[1] = arr[1];
		len = 1;
		for (i = 2; i <= p; ++i) {
			if (arr[i] > ans[len])
				ans[++len] = arr[i];
			else {
				int pos = lower_bound(ans + 1, ans + len + 1, arr[i]) - ans;
				ans[pos] = arr[i];
			}
		}
		printf("%d\n", len);
	}
	system("pause");
	return 0;
}

 

引用:

LIS的nlogn的优化:
LIS的优化说白了其实是贪心算法,比如说让你求一个最长上升子序列把,一起走一遍。

比如说(4, 2, 3, 1, 2,3,5)这个序列,求他的最长上升子序列,那么来看,如果求最长的上升序列,那么按照贪心,应该最可能的让该序列的元素整体变小,以便可以加入更多的元素。
现在开辟一个新的数组,arr[ 10 ], { .......} --> 这个是他的空间 ,现在开始模拟贪心算法求解最长上升子序列,第一个数是4,先加进去,那么为{ 4 }再来看下一个数2,它比4小,所以如果他与4替换是不是可以让目前子序列(他这一个元素组成的子序列)变得更小,更方便以后元素的加入呢?是的。所以现在为{ 2 } 再来看他的下一个元素3,他要比2大,所以呢加在他的后面,{ 2, 3}
再看下一个元素是1,它比3要小,所以呢为了保证子序列整体尽可能的小(以便可以加入更多的元素),从目前的序列中查找出第一个比他大的数替换掉,那么就变成了{ 1, 3},继续。。 下一个数是2,那么序列变为{ 1,2},再下一个数为3,那么序列为{1,2,3},在下一个数为5,那么序列为{1,2,3,5},完。 目前序列里又4个元素,所以他的最长子序列的个数为4,但是这个序列是一个伪序列,里面的元素,并不是真正的最长上升子序列,而仅仅和最长上升子序列的个数一样。因为查找的时候用的二分查找,所以时间复杂度为o(nlogn)。
————————————————
版权声明:本文为CSDN博主「ltrbless」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ltrbless/article/details/81318935

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值