正在网易云课堂学习王宏志老师的算法设计与分析入门篇课程视频,将学习中的作业问题发上来与大家一同讨论。这篇是对第四周的作业第一题个人的一些思路,希望与大家一同学习。
题目内容:
给定有 n 个整数组成的数列 {A_n},记为:A_1、A_2、……、A_n。
A 的一个不降子序列,为 {B_m},满足 1<= B_i <= n 且对于所有的 1 <= i < m,满足:
Bi < B_{i+1},并且 A_{B_i} <= A_{B_{i+1}}。
例如 {A_n} = 3,18,7,14,10,12,23,41,16,24。
如上例中 3,18,23,24 就是一个长度为 4 的不下降序列,同时也有 3,7,10,12,16,24 长度为 6 的不下降序列。
求所有 {A_n} 的不降子序列中,最长的长度。
输入格式:
输入数据的第一行包含一个整数 n。(1\leq n \leq 10^5)
接下来的一行,包含 n 个整数 A_i。(1\leq A_i \leq 10^9)
输出格式:
输出一行表示答案。
输入样例:
输出样例:
比较坑,没明确说明输出个数还是数组。
思路:记录从1到max(最长长度)所有子序列的最末位数,然后不断用更小的数更新。
如:6 12 8 1 9 4 3 6 7 8 10
第一次读入6,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 6 |
读入12,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 6 | 12 |
读入8,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 6 | 8 |
长度为2的不降子序列末尾最小为8,子序列为 6,8
读入1,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 8 |
长度为1的不降子序列末尾最小为1,子序列为 1,
读入9,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 8 | 9 |
最长不降子序列长度加1,子序列为 1,8,9
读入4,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 4 | 9 |
长度为2的不降子序列末尾最小为4,子序列为 1,4
读入3,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 3 | 9 |
长度为2的不降子序列末尾最小为3,子序列为 1,3
读入6,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 3 | 6 |
长度为3的不降子序列末尾最小为6,子序列为 1,3,6
读入7,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 3 | 6 | 7 |
最长不降子序列长度加1,子序列为 1,3,6,7
读入8,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 3 | 6 | 7 | 8 |
最长不降子序列长度加1,子序列为 1,3,6,7,8
读入10,
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
末尾数 | 1 | 3 | 6 | 7 | 8 | 10 |
最长不降子序列长度加1,子序列为 1,3,6,7,8,10
代码如下:
int max = 1;
d[0] = p[0];
for (int i = 1; i < n; i++){
int j = 0;
for (; j < max; j++){
if (p[i] < d[j]){
d[j] = p[i];
break;
}
}
if (j == max){
d[max] = p[i];
max++;
}
}
cout << max<<"\r\n";
这是不要求输出子列内容的,时间复杂度为 n^2。如果要求输出子列内容,则可以开一个n*n的二维数组,记录路径。不过,每次最长不降子序列长度加1是,都要拷贝路径,时间复杂度就要达到 n^3。
动态规划使用循环与递归都可以实现,循环的效率能更高一点。但不是说循环比递归好,用什么方法,全凭个人兴趣。