1. 问题描述:在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是不下降的(非递减的)
例如现有序列A = {1,2,3,-1,-2,7,9}(下标从1开始)它的最长不下降子序列是{1,2,3,7,9}长度为5,还有一些子序列是不下降子序列,比如{1,2,3}、{-2,7,9}但是不是最长的
2. 思路分析:
① 首先我们可以枚举所有的元素,使用双层循环来进行开始序列和结束序列,第一层循环扫描开始序列,第二层循环扫描结束序列,在第二层循环的时候扫描以开始序列之后的数字,并且定义指针表示当前不下降子序列所处的位置,往后进行扫描的过程中,假如发现后面元素的位置假如大于了指针指向的位置,那么不下降子序列加1,而且指针往后移动一位,等到第一层循环结束那么以当前开始位置序列的不下降子序列的长度就知道了,我们在一开始的时候就定义一个全局变量max来记录当前最长不下降子序列的长度,等到第一层循环结束的时候那么我们决定是否更新当前的最长不下降子序列的长度,由于存在着双层循环那么时间复杂度是O(n ^ 2)
② 除了使用上面的方法解决之外,我们还可以使用经典的方法来解决,可以使用动态规划的思想来解决,定义一个dp数组,数组表示的含义是以A[i]结尾的最长不下降子序列的长度,对于A[i]来说存在着两种情况:
1)如果存在A[i]之前的元素A[j](j < i)使得A[i] >= A[j],也就是将A[i]放在A[j]结尾的LIS后面的时候比以A[i]结尾的LIS长度更长,那么就将A[i]跟在以A[j]结尾的LIS后面,形成一条更长的不下降子序列
2)如果A[i]之前的元素都比A[i]大,那么A[i]治好自己形成一条LIS,但是长度为1,即这个子序列里面只有一个A[i]
最后以A[i]结尾的LIS长度就是1)2)形成的最大长度
测试数据:
8
1 2 3 -9 3 9 0 11
输出:6
3. 下面是具体的代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int n = 100;
int A[n], dp[n];
int main(void){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", &A[i]);
}
int ans = -1;
for(int i = 1; i <= n; ++i){
dp[i] = 1;
for(int j = 1; j < i; ++j){
if(A[i] >= A[j] && (dp[j] + 1 > dp[i])){
dp[i] = dp[j] + 1;
}
}
ans = max(ans, dp[i]);
}
printf("%d", ans);
return 0;
}