最长上升子序列-二、问题简析

2.1 法一: O ( N 2 ) O(N^2) O(N2)

d p [ i ] = dp[i]= dp[i]= a i a_i ai 结尾的上升子序列的最大长度
a i a_i ai 结尾的上升子序列有两种可能:

  • 1、仅有 a i a_i ai 一个元素
  • 2、在满足 j < i j < i j<i a j < a i a_j < a_i aj<ai 的以 a j a_j aj 结尾的上升子序列结尾,加上 a i a_i ai

所以,递归方程为:

d p [ i ] = m a x ( 1 , d p [ j ] + 1 )       , j < i   a n d   a j < a i dp[i]=max(1,dp[j]+1)~~~~~,j<i~and~a_j<a_i dp[i]=max(1,dp[j]+1)     ,j<i and aj<ai

最终结果是 d p [ i ] dp[i] dp[i]最大值


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int quickin(void)
{
	int ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 5e3 + 3;
int A[MAX], n, dp[MAX];

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	n = quickin();
	for (int i = 0; i < n; i++)
		A[i] = quickin();
	int ans = 0;
	for (int i = 0; i < n; i++)
	{
		dp[i] = 1;
		for (int j = 0; j < i; j++)
		{
			if (A[j] < A[i])
				dp[i] = max(dp[i], dp[j] + 1);
		}
		ans = max(ans, dp[i]);
	}
	cout << ans << endl;
	
	return 0;
}

2.2 法二: O ( N l o g N ) O(NlogN) O(NlogN)

d p [ i ] = dp[i]= dp[i]= 长度为 i + 1 i+1 i+1 的上升子序列的末尾元素的最小值。(因为对于相同长度的上升子序列,结尾元素越小,就越有优势)
对于每个 d p [ i ] dp[i] dp[i],遍历 a j a_j aj,若 i = = 0 i==0 i==0 a j > d p [ i − 1 ] a_j > dp[i - 1] aj>dp[i1],不断更新 d p [ i ] = m i n ( d p [ i ] , a j ) dp[i]=min(dp[i],a_j) dp[i]=min(dp[i],aj)。最终,使 d p [ i ] < I N F dp[i] <INF dp[i]<INF 的最大的 i + 1 i+1 i+1 就是所求。如果按这个思路,仍然是 O ( N 2 ) O(N^2) O(N2)

因为 d p [ i ] dp[i] dp[i] 是升序,所以我们可以选择用二分搜索来优化。遍历 a j a_j aj,在 d p [ i ] dp[i] dp[i] 中查找首个不小于lower_bound a j a_j aj d p [ i ] dp[i] dp[i] ,并赋值 a j a_j aj。最终,使 d p [ i ] < I N F dp[i] <INF dp[i]<INF 的最大的 i + 1 i+1 i+1 就是所求。


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int quickin(void)
{
	int ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 5e3 + 3;
const int INF = 1e8;
int A[MAX], n, dp[MAX];

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	n = quickin();
	for (int i = 0; i < n; i++)
		A[i] = quickin();
	
	fill(dp, dp + n, INF);
	for (int i = 0; i < n; i++)
	{
		*lower_bound(dp, dp + n, A[i]) = A[i];
	}
	cout << lower_bound(dp, dp + n, INF) - dp << endl;
	
	return 0;
}

上一篇:Qt——2D画图


下一篇:物理设计概念 -- 包