目录
题目描述
给出一个由n个正整数组成的数组。您的任务是找到给定数组的递增子数组的最大长度。
递增子数组由数组中若干个连续元素组成,且子数组中的每个元素严格地大于前一个元素。
【输入形式】
第一行为一个正整数n(1≤n≤),表示数组元素的个数
第二行给出n个正整数a1 a2......an (1≤ai≤) ,整数之间使用空格分隔
【输出形式】
输出最大递增子数组的长度
【样例输入】
5
1 7 2 11 15
【样例输出】
3
【样例说明】
1 7可以构成一个递增子数组
2 11 15可以构成一个递增子数组
所以本样例的输出结果为3
思路分析
直接采用穷举法,二重循环遍历,时间复杂度为O()。
设一个数组int arr:
0 | 1 | 2 | 3 | 4 |
1 | 7 | 2 | 11 | 5 |
设整型变量cnt=1(任意长度大于0数组的最长连续递增子序列最小长度为1),记录当前子数组最长连续递增子序列的长度。子数组分割方法如下:
第一次 | arr[0],arr[1],arr[2],arr[3],arr[4] | cnt=2 |
第二次 | arr[1],arr[2],arr[3],arr[4] | cnt=1 |
第三次 | arr[2],arr[3],arr[4] | cnt=3 |
第四次 | arr[3],arr[4] | cnt=1 |
第五次 | arr[4] | cnt=1 |
最终结果输出3。
AC代码
#include <iostream>
#include<stdio.h>
using namespace std;
int arr[100000]={0};
int main()
{
int n;
cin >> n;
for(int i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
int Max=0;
for(int i=0;i<n;i++)
{
int cnt=1;
for(int j=i;j<n-1;j++)
{
if(arr[j]<arr[j+1])
{
cnt++;
}
else
{
break;
}
}
if(cnt>Max)//取所有cnt中的最大值
{
Max=cnt;
}
}
printf("%d\n",Max);
}
深入思考
其实这题是一个典型的动态规划问题的变式。
动态规划基本知识:
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。
动态规划算法跟数组有着密切的关系,因此推荐大家在分析动态规划的算法时画一张表格(建议使用excel)分析解决问题往往能够事半功倍。
(引自 CSDN博主「静笃归心方得平和心气]
原文链接:https://blog.csdn.net/weixin_42182348/article/details/90814032)
最大递增子数组问题(不要求连续)
给定数组arr,返回arr的最长递增子序列(Longest increasing subsequence,LIS)的长度,比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9]返回其长度为5。
那么,这个问题怎么用动态规划法求解呢?
设f[i]表示必须以arr[i]结尾的所有子数组的LIS。要计算f[i],就要考察i之前的所有位置(0到i-1,这就是代码内层for的控制变量j的变化范围),找到最大的f[j]。f[j]代表以arr[j]结尾的子数组中最大递增子序列的长度。
注意到,由于它是递增的,因此arr[j]就是子序列的最大值。如果arr[i]比arr[j]还大,那就一定大于该序列中的其他数,能够构成一个长度+1的LIS。这就是if中的第一个条件的来源。
第二个条件是为了保证更新f[i]的结果是得到更大的f[i]值。说起来不太直观,请看下表。
序号i | 0 | 1 | 2 | 3 | 4 | ... |
arr[i] | 11 | 13 | 19 | 5 | 21 | ... |
f[i] | 1 | 2 | 3 | 1 | ? | ... |
此刻i=4。假设没有if中的第二个条件(f[i]<f[j]+1),求f[4]的详细过程为:
j | 0 | 1 | 2 | 3 |
f[4] | 2 | 3 | 4 | 2 |
arr[0]<arr[4] f[4]=f[0]+1=2
arr[1]<arr[4] f[4]=f[1]+1=3
arr[2]<arr[4] f[4]=f[2]+1=4
arr[3]<arr[4] 但是此时f[3]=1,f[4]=4(见上一行), 不满足f[i]<f[j]+1。更新后 f[4]=f[3]+1=2(反而变小了)
而带上(f[i]<f[j]+1)这个条件的话,j=3这次循环就不会更新f[4]的值,最终算出f[4]的正确值为4。
代码
#include <iostream>
#include<stdio.h>
using namespace std;
int arr[100000]={0};
int f[100000]={0};//记录子数组的LIS。
int main()
{
int n;
cin >> n;
for(int i=0;i<n;i++)
{
cin >> arr[i];
f[i]=1;//初始化
}
int Max=0;//记录以不同元素结尾的子数组的LIS的最大值。
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{
if((arr[j]<arr[i])&& (f[i]<f[j]+1))
{
f[i]=f[j]+1;//f[i]记录了必须以arr[i]结尾时所有子数组的LIS。
}
}
if(f[i]>Max)
{
Max=f[i];
}
}
cout << Max << endl;
return 0;
}