最长递增子序列的思索
来源:互联网 发布:复杂网络应用实例 编辑:程序博客网 时间:2024/06/16 20:42
这是一个比较古老的算法问题,在上学期的算法课中也有所讲解,不过当初并没有理解到位,现在重新思考一下。
最长递增子序列问题:给定一个序列{a0,…,ai},找出其中最长的一个序列{b0,…,bj},并且满足对任意的 0 < n,m < j,都有bn < bm。
最朴素的一种解法是从a0开始,对给定序列进行遍历,在遇到分叉时产生分支,最后将最长的序列更新出来。遍历到an时便得到最大的递增序列。这种做法较为简单,但是不可取,因为对每一个ai而言求以它为开头的递增序列可能会产生大量分支,严重影响了求解速度。
对上面的解法我们可以增加一个剪枝,如果当前要进行遍历的元素是前面某一个最长序列的一部分,那么他的序列长度肯定较小,便可以跳过此元素,直接判断下一个即可。
但是这样还是很慢,一个只有1000个数的序列,要找出最长子序列大概需要2s,这是不可容忍的,所以我搬出了动态规划。在这个问题里面,前n的数与前n-1个数的最长链有一定的联系。如果第n个数大于前面n-1个数中最长链的末端,那么更新,否则寻找链中合适的元素重新构成子序列(自身有可能是头元素)。
对这个算法,我想出了以下解法:
对每个元素为末尾进行遍历,对第i个元素,需要遍历前i-1个元素的最长子序列进行判断。然后按照算法更新相关数据,这样可以保证到第n个元素的时候一定是最长子序列。最后我按逆序输出,如果顺序输出的话单独开个数组存储一下就好。
//关于最长子序列问题的思索#include<stdio.h>int data[1000];//存储数据int answer[1000];//最长链长度int list[1000];//前导元素int max;//最长链int index;//最长链末尾索引int main(){ int n; int i,j; while(~scanf("%d",&n)){ for(i = 0; i < n; i++) scanf("%d",&data[i]); answer[0] = 1; list[0] = 0; max = 1; index = 0; for(i = 1; i < n; i++){ answer[i] = 1; list[i] = i; for(j = i - 1; j >= 0; j--){ if(data[j] < data[i] && answer[j] + 1 > answer[i]){ answer[i] = answer[j] + 1; list[i] = j; } } if(answer[i] > max){ max = answer[i]; index = i; } } n = list[index]; while(n != index){ printf("%d ",data[index]); index = n; n = list[index]; } printf("%d\n",data[n]); } return 0;}
这个相比之前速度快了很多,一个1000的序列,大概100ms左右可以解决。那么还能优化吗?关键点应该在于在求前n个数的时候要对前n-1个数进行遍历,如果我们能够使用二分的思想优化,那么这个问题的时间就从一个n^2减小到nlog(n)。
#include<stdio.h>int search(int );int count;int answer[1000];int main(){ int i,n; int number; while(~scanf("%d",&n)){ count = 0; scanf("%d",&answer[0]); for(i = 1; i < n; i++){ scanf("%d",&number); if(number < answer[0]) answer[0] = number; else if(number > answer[count]) answer[++count] = number; else{ answer[search(number)] = number; } } printf("%d\n",count+1); }}int search(int number){ int begin = 0,end = count; int mid = (begin + end) / 2; while(begin <= end){ if(answer[mid] < number) begin = mid + 1; else if(answer[mid] == number) return mid; else end = mid - 1; mid = (begin + end) / 2; } return mid + 1;}
这种方法占用内存较少 如果只是计数的话并不用存储之前的结果。
如果要输出最长链 只需要单独申请一个数组用来存储最长链 通过对比链中元素在最长链长度改变时进行相关的更新
- 最长递增子序列的思索
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- Hibernate与 MyBatis的比较
- 152. Maximum Product Subarray
- 刷题--树的子结构
- Windows 窗口层次关系(转)
- copy和mutable copy
- 最长递增子序列的思索
- 线段树入门
- uC/OS-III之资源管理--互斥型信号量
- “共享经济”的风催熟了“信用经济”
- C++对象构造函数失败会直接回收已分配的内存
- B. Sagheer, the Hausmeister(codeforce 417 div2 B, dfs)
- 自定义配置 mpv 播放器
- 记录一些常用的utils方法6
- 【tensorflow学习】BasicLSTMCell 源码分析