最长上升子序列 (Longest Increasing Subsequence, 常简称为 LIS) 是动态规划解决的一个经典问题。 我们先讲一下子序列是什么。一个数组的子序列就是从里面选出一些元素,并将他们保持原有的先后顺序排列。比如[1, 2, 3, 4, 5]的子序列有[1, 3, 5]、[3, 4],而[1, 5, 3]则不是这个数组的子序列。 这里多介绍一下,还有一个容易与子序列混淆的概念:子串。子串是指从一个数组中选出连续的一个或多个元素,并且保持他们原有的顺序。子串一定是子序列,比如前面的子序列[3, 4]就是子串,但[1, 3, 5]不是子串,因为这三个元素在原数组中并不是连续的。 一句话总结他们的区别,就是子序列可以不连续,而子串必须连续。 上升子序列是指子序列Ai中满足 A1 < A2 < ... < An,也就是后面的元素一定比前面的元素大,比如(1, 3, 5)是上升子序列,(1, 3, 3)和(1, 4, 3)都不是。现在来跟我一起解决最长上升子序列的问题吧!(o・・o)/ 输入格式: 第一行一个整数n(1 ≤ n ≤ 100),表示序列的长度。 第二行 n 个整数,表示序列中的每个元素。 输出格式: 输出只有一行,为最长上升子序列的长度
序列 1 5 2 3 4
两个for循环,num[j]是num[i]的内层
从第i=1个开始,第一次循环j=1;由于num[i]与num[j]是同一个所以马上退出内层循环。
result=max(dp[i], result);这里更新最大子序列的值。
i=2, j=1:在num[1] < num[2],所以执行dp[2] = max(dp[1]+1, dp[2]).这句代码就是状态转移。
继续j++,不符合条件就退出内层循环,从而进入第三次循环。
result=max(dp[i], result);这里更新最大子序列的值。
i=3,j=1;内层第一次循环,j=1时,num[1] < num[3],所以dp[3]=max(dp[1]+1, dp[3]);
j=2时,num[2]>num[3],不执行状态转移的代码,然后j++,j=3,不符合条件,退出内层循环。
result=max(dp[i], result);这里更新最大子序列的值。
i=4, j=1时,num[1]<num[4],所以dp[4]]=max(dp[1]+1, dp[4]);
j=2, num[2]>num[4], 不执行状态转移的代码
j=3, num[3]<num[4], 所以dp[4]=max(dp[3]+1,dp[4])
j=4,退出内层循环。
result=max(dp[i], result);这里更新最大子序列的值。
i=5, j=1时,num[1]<num[5],所以dp[5]=max(dp[1]+1, dp[5]);
j=2, num[2]>num[5], 不执行状态转移的代码
j=3, num[3]<num[5], 所以dp[5]=max(dp[3]+1,dp[5])
j=4, num[4]<num[5], 所以dp[5]=max(dp[4]+1,dp[5])
result=max(dp[i], result);这里更新最大子序列的值。
然后退出外层循环。
最后输出result即可。
#include <iostream>
#include <cstdio>
using namespace std;
int n, dp[101], num[101], result = 0;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
}
for(int i = 1; i <= n; i++)
{
dp[i] = 1;
for(int j = 1; j < i; j++)
{
if(num[j] < num[i])
{
dp[i] = max(dp[j]+1, dp[i]);
}
}
result = max(result, dp[i]);
}
printf("%d\n", result);
return 0;
}