poj 2533 最长递增子序列

求解最长递增子序列算法详解
本文详细解析了求解最长递增子序列的问题,包括三种不同的解题方法,其中重点介绍了方法二和方法三,后者通过使用二分搜索优化了算法效率。文章深入探讨了每种方法的原理、实现细节以及应用背景。

题目大意:求最长递增子序列

解题思路:这道题,编程之美上有详细解答,

设lis[i]表示已第i个数字结尾的递增子序列的长度

lis[i+1] = max(1, lis[k] + 1) array[i+1] > array[k], k <= i

编程之美上方法一不介绍了,

这里介绍下方法二

增加一个数组mav[i]表示长度为i的最长递增子序列中的最大元素中的最小值

那么寻找那个满足条件的k时,不需要从 i 开始往后遍历找

#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
using namespace std;

const int maxn = 1010;
int n;
int array[maxn], maxv[maxn], lis[maxn];
int main()
{
		scanf("%d", &n);
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &array[i]);
		lis[i] = 1;
	}
	lis[0] = -1;
	maxv[1] = array[1];
	maxv[0] = INT_MIN;
	int maxlis = 1;
	for(int i = 1; i <= n; i++)
	{
		int j;
		for(j = maxlis; j >= 0; j--)
		{
			if(array[i] > maxv[j])
			{
				lis[i] = j + 1;
				break;
			}
		}
		
		if(lis[i] > maxlis)
		{
			maxlis = lis[i];
			maxv[maxlis] = array[i];
		}
		else if(maxv[j] < array[i] && array[i] < maxv[j + 1])
		{
			maxv[j + 1] = array[i];
		}
	}
	printf("%d\n", maxlis);
		return 0;
}

方法3:

for(j = maxlis; j >= 0; j--)
  {
   if(array[i] > maxv[j])
   {
    lis[i] = j + 1;
    break;
   }
  }

在求那个j时,改用二分搜索查询,可以把O(n^2)降为O(nlogn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
using namespace std;

const int maxn = 1010;
int n;
int array[maxn], maxv[maxn], lis[maxn];

int binarysearch(int low, int high, int index);

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &array[i]);
		lis[i] = 1;
	}
	lis[0] = -1;
	maxv[1] = array[1];
	maxv[0] = INT_MIN;
	int maxlis = 1;
	for(int i = 1; i <= n; i++)
	{ 
		int j = binarysearch(1, maxlis, i);
		if(j != -1)
			lis[i] = j + 1;
		else
			j = 0;
		if(lis[i] > maxlis)
		{
			maxlis = lis[i];
			maxv[maxlis] = array[i];
		}
		else if(maxv[j] < array[i] && array[i] < maxv[j + 1])
		{
			maxv[j + 1] = array[i];
		}
	}
	printf("%d\n", maxlis);
		return 0;
}

int binarysearch(int low, int high, int index)
{
	int pre = -1;
	while(low <= high)
	{
		int mid = (low + high) >> 1;
		if(array[index] > maxv[mid])
		{
			pre = mid;
			low = mid + 1;
		}
		else
			high = mid - 1;
	}
	return pre;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值