利用动态规划找出最长公共单调递增子序列
来源:互联网 发布:mysql blob 中文乱码 编辑:程序博客网 时间:2024/05/20 21:23
1.设计一个O(n²)时间的算法。
方法如下:
①利用快速排序先将原序列排序。
②然后再计算原序列和已排序序列两者公共子序列。
③打印公共子序列。
代码如下:
/************************************************************************/ /* 算法导论15.4-5 * 找出n个数的序列中最长的单调递增子序列 * 时间复杂度为O(n^2)*/ /************************************************************************/ #include <iostream>#include <time.h>using namespace std;#define N 11char *b[N+1][N+1]={NULL};int c[N+1][N+1]={0};void Lcs_Length(int *x,int *y) {for (int i1=0;i1<=N;i1++){b[i1][0]="NULL";}for (int j1=0;j1<=N;j1++){b[0][j1]="NULL";}for (int i=1;i<=N;i++){for (int j=1;j<=N;j++){if (x[i]==y[j]){c[i][j]=c[i-1][j-1]+1;b[i][j]="↖";}else{if (c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]="↑";} else{c[i][j]=c[i][j-1];b[i][j]="←";}}} }}void PRINT_LCS(int*x,int i,int j){if (i==0||j==0){return;}if (b[i][j]=="↖"){PRINT_LCS(x,i-1,j-1);cout<<x[i]<<" ";}else{if (b[i][j]=="↑"){PRINT_LCS(x,i-1,j);} else{PRINT_LCS(x,i,j-1);}}}int PARTITION(int A[],int p,int r){ int x=A[r]; int i=p-1; for (int j=p;j<=r-1;j++)//O(n) { if (A[j]<=x) { i++; swap(A[i],A[j]); } } swap(A[i+1],A[r]); return i+1;}void QUICKSORT(int A[],int p,int r){ if (p<r) { int q=PARTITION(A,p,r); QUICKSORT(A,p,q-1); QUICKSORT(A,q+1,r); }}void printSequence(int *b,int* nums,int last);void main(){//为了和书中代码吻合,数组第一个位置存放空字符。 srand( (unsigned)time( NULL ) );//int x[N+1] ={0};int y[N+1] ={0};for (int i=1;i<=N;i++){y[i]=x[i]=rand()%10+1;cout<<x[i]<<" ";}cout<<endl;QUICKSORT(y,0,N);//①利用快速排序先将原序列排序。Lcs_Length(x, y);//②然后再计算原序列和已排序序列两者公共子序列。PRINT_LCS(x,N,N);//③打印公共子序列。cout<<endl;cout<<"书中图15-8中的表格:"<<endl;for ( i=0;i<=N;i++){for (int j=0;j<=N;j++){cout<<b[i][j]<<" ";}cout<<endl;for (j=0;j<=N;j++){cout<<c[i][j]<<" ";}cout<<endl;} }
2.设计一个O(nlgn)时间的算法。
①如果当前元素比当前子序列中所有元素都大则最长递增子序列的长度加一。
②否则使用二分法在当前子序列中查找到大于等于当前元素的最小元素,用当前元素替换这个最小元素。
参考代码(我精简并更改了参考代码):点击打开链接
代码如下:
/************************************************************************/ /* 算法导论15.4-6 * 找出n个数的序列中最长的单调递增子序列 * 时间复杂度为O(nlgn)*/ /************************************************************************/ #include <iostream>#include <vector>#include <time.h>using namespace std;#define N 11void printSequence(int *b,int* nums,int last); void main(){srand( (unsigned)time( NULL ) ); int nums[N+1]={0}; cout<<"原序列长度为"<<N+1<<",如下:"<<endl; for (int i=0;i<=N;i++){nums[i]=rand()%1000+1;cout<<nums[i]<<" ";} //数组b存储在递增子序列中当前元素的前一个元素序号 int b[N+1]={0}; //数组b存储在递增子序列中当前元素的前一个元素序号,根据数组b我们能回溯整个子序列 int last[N+1]={0},L=0; //last中存储各不同长度的递增子序列(同一长度的子序列,只考虑尾元素最小的序列)中最后一个元素的序号,根据last数组我们能找到最长子序列的最后一个元素序号。 for ( i=1;i<N+1;i++)//所以我们用last数组找到MAX子序列最后一个元素下标后,利用数组b回溯整个MAX子序列。 { int low=0,high=L-1; if(nums[i]>nums[last[L==0?0:high]]) {//如果当前元素比last中所有元素都大则最长递增子序列的长度加一,其尾元素为当前元素nums[i] last[L++]=i; b[i]=last[high]; }else{//否则使用二分法在last中查找到大于等于当前元素nums[i]的最小元素 while(low<=high) { int middle=(high+low)/2; if(nums[i]>nums[last[middle]]) low=middle+1; else high=middle-1; } //更新last中的元素值和b中的下标值。 last[low]=i; b[i]=last[low==0 ? 0 : low-1]; } } int len=L;cout<<endl; cout<<"公共子序列如下:"<<endl; printSequence(b,nums,last[len-1]); cout<<endl; }void printSequence(int *b,int* nums,int last) { //回溯法 if(b[last]!=last) printSequence(b,nums,b[last]); cout<<nums[last]<<" "; }
0 0
- 利用动态规划找出最长公共单调递增子序列
- 动态规划:最长单调递增子序列
- 动态规划--最长单调递增子序列
- 【动态规划】单调递增最长子序列
- 最长单调递增子序列--动态规划
- 找出n个数组成的最长单调递增子序列( 动态规划O(nlogn) )
- NYOJ - 17 - 单调递增最长子序列(动态规划--LIS--单调递增最长子序列)
- 动态规划题目一:最长单调递增子序列
- nyoj17单调递增最长子序列--动态规划-初步
- 动态规划之单调递增最长子序列
- 动态规划-单调递增最长子序列(三)
- NYOJ17 单调递增最长子序列 【二分法】+【动态规划】
- 单调递增最长子序列--动态规划的经典题目
- ny17单调递增最长子序列(动态规划)
- 单调递增最长子序列 (动态规划经典题)
- NYOJ 17 单调递增最长子序列(动态规划)
- 最长单调递增子序列——动态规划
- 单调递增最长子序列(动态规划)
- jQuery添加新元素/内容
- leetcode Binary Tree Postorder Traversal
- cmd命令大全
- hdu1603
- java读取中文分词工具(三)
- 利用动态规划找出最长公共单调递增子序列
- 重置iOS simulator
- 拓扑排序
- Ubuntu客户端通过WINS查找NetBIOS名称
- 东大OJ-5到100000000之间的回文质数
- [Bluetooth(SDK)]蓝牙协议栈架构
- jquery file upload报错 TypeError: Object [object Object] has no method 'progressbar'
- iOS开发学习笔记 2-9 C语言部分 内存分配函数 函数指针 指针函数 void*
- Datastage中使用Routine程序执行多条shell指令