最长上升子序列
描述
一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
你的任务,就是对于给定的序列,求出最长上升子序列的长度。
输入
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
输出
最长上升子序列的长度。
样例输入
7
1 7 3 5 9 4 8
样例输出
4
分析:
1.最优子结构问题:
在一个数据串中,如: 1 7 3 5 9 4 8,如果我要求解在9的时候,求出最长的上升子序列,其实,平时最简单的方法就是,
我能不能在已经前面计算过的的所有的最长序列中,找到一个最长的,再把自己这个元素加上去;
2.子问题重叠:
每一次都是在前面的每一个一个元素中,找到最长的个数了,所以,重叠问题很多,每到一个元素,就必须去求解前面的元素的最长个数 ,
考虑到这点,如果是用一个数组将每一个元素的所求的解都储存,那就不是将时间复杂度减下来了吗?;
3.边界:
肯定就是第一个元素了,第1个元素的最长上升子序列就是1啦,所以就有dp[0] = 1;注意,下标从0 开始
4.子问题独立:
每一次的求解都是一个子问题,和后面的数字没有关系;
5:选择个数:可以是判断的次数:这个题目的选择个数是和他的访问的个数有关,所以是不确定的,但是有规律,就是访问到第几个数据,就有几次判断;
6.递推方程:dp[i] = Max(dp[j])+1;其中j的范围是0<=j<i;前提是Va[j]<Va[i];
7.备忘录的制作:这里的备忘录就是一个一位的数组就OK了,不存在滚动数组;
#include <iostream>
#include <algorithm>
#include <cstring>
#define NUM 1005
using namespace std;
int main()
{
int Va[NUM];//数据数组
int dp[NUM];//表示储存最长的子序列的个数数组
int N;//表示数据个数
cin>>N;
if(N==0)
{cout <<0<<endl;return 0;}
for(int i = 0;i<N;i++)
{cin>>Va[i];dp[i] = 1;}
// for(int i = 0;i<N;i++)
// cout <<Va[i]<<" ";
// cout <<endl;//测试
dp[0] = 1;
//初始化dp的起点;
for(int i = 1;i<N;i++){
for(int j = 0;j<i;j++)
if(Va[i]>Va[j])//这是满足的前提;
dp[i] = max(dp[i],dp[j]+1);
}
//for(int i = 0;i<N;i++)
// cout <<dp[i]<<" ";
// cout <<endl;//测试
cout <<*max_element(dp, dp+N)<<endl;
return 0;
}