算法导论 习题15.4-5 15.4-6 找出一个n个数的序列中最长的单调递增子序列
2014-04-24 12:48
381 查看
算法导论15.4-5 请给出一个O(n^2)时间的算法,使之能找出一个n个数的序列中最长的单调递增子序列。
这个题目是在动态规划部分,此处显然是要用到动态规划。
我们知道可以使用动态规划思想的问题的的两个重要的特征是具有最优子结构和重叠子问题。下面就来分析一下这个问题:
对于一个n个元素的序列nums,设其最长单调递增子序列为Sm(n)(m为递增子序列的长度),则对于Sm存在两种情况:
1、如果nums
比Sm-1的最后一个元素大,则Sm由Sm-1加nums
组成
2、如果nums
小于等于Sm-1的最后一个元素,则Sm即为Sm-1
但是这样考虑有问题,因为如果Sm-1的序列有多个,我们则应该每一个都与nums
考察,如果nums
比所有Sm-1的尾元素都小或相等,而Sm-2的序列中又存在尾元素小于nums
的序列,则我们应该如何选择,Sm应该是多少? Sm-1+nums
、Sm-1、Sm-2+nums
所以之前的分析是有问题的,在长度相同的情况下,我们优先选择包含nums
的序列作为Sm(n),因为每一个新加入的元素都可能改变不同长度的递增子序列,因此我们需要维护每一个递增子序列以获取最优。
这里的最优子结构就是n个元素的最长递增子序列是从前n-1个元素结尾的递增子序列中的一个或者再加上nums
,这里面自然存在很多重叠子问题。
代码如下:
以上程序的时间复杂度是O(n^2),共有n个子问题,每个子问题有n个选择。
15.4-6又要求用O(nlgn)的时间复杂度来找出最长递增子序列,具体的算法思想可以参考:
/article/8026752.html
下面我直接上代码
这个题目是在动态规划部分,此处显然是要用到动态规划。
我们知道可以使用动态规划思想的问题的的两个重要的特征是具有最优子结构和重叠子问题。下面就来分析一下这个问题:
对于一个n个元素的序列nums,设其最长单调递增子序列为Sm(n)(m为递增子序列的长度),则对于Sm存在两种情况:
1、如果nums
比Sm-1的最后一个元素大,则Sm由Sm-1加nums
组成
2、如果nums
小于等于Sm-1的最后一个元素,则Sm即为Sm-1
但是这样考虑有问题,因为如果Sm-1的序列有多个,我们则应该每一个都与nums
考察,如果nums
比所有Sm-1的尾元素都小或相等,而Sm-2的序列中又存在尾元素小于nums
的序列,则我们应该如何选择,Sm应该是多少? Sm-1+nums
、Sm-1、Sm-2+nums
所以之前的分析是有问题的,在长度相同的情况下,我们优先选择包含nums
的序列作为Sm(n),因为每一个新加入的元素都可能改变不同长度的递增子序列,因此我们需要维护每一个递增子序列以获取最优。
这里的最优子结构就是n个元素的最长递增子序列是从前n-1个元素结尾的递增子序列中的一个或者再加上nums
,这里面自然存在很多重叠子问题。
代码如下:
/************************************************************************/ /* 算法导论15.4-5 * 找出n个数的序列中最长的单调递增子序列 * 利用动态规划思想,时间复杂度为O(n^2)*/ /************************************************************************/ #include<iostream> using namespace std; void printSequence(int *b,int* nums,int last); int main() { int n=8; int nums[9]={0,1,7,8,9,2,3,4,5}; //b存储当前元素所在递增子序列中当前元素的前一个元素序号 //c存储以当前元素结尾的递增子序列长度 //last存储当前元素为止的序列中最长递增子序列的最后一个元素的序号 //maxLen存储当前最长递增子序列的长度 int b[9]={0},c[9]={0},last[9]={0},maxLen=0; c[1]=1,last[1]=1; for (int i=1;i<=n;i++) { for (int j=1;j<i;j++) { if(nums[j]<nums[i] && c[j]+1>c[i]) { c[i]=c[j]+1; b[i]=j; last[i]=i; maxLen=c[i]; }else if(c[j]>c[i]){ maxLen=c[j]; last[i]=last[j]; } } } cout<<"原序列长度为"<<n<<",如下:"<<endl; for (int i=1;i<=n;i++) { cout<<nums[i]<<" "; } cout<<endl<<"最长递增子序列长度为"<<maxLen<<",如下:"<<endl; printSequence(b,nums,last ); cout<<endl; return 0; } void printSequence(int *b,int* nums,int last) { if(b[last]>0) printSequence(b,nums,b[last]); cout<<nums[last]<<" "; }
以上程序的时间复杂度是O(n^2),共有n个子问题,每个子问题有n个选择。
15.4-6又要求用O(nlgn)的时间复杂度来找出最长递增子序列,具体的算法思想可以参考:
/article/8026752.html
下面我直接上代码
/************************************************************************/ /* 算法导论15.4-6 * 找出n个数的序列中最长的单调递增子序列 * 时间复杂度为O(nlgn)*/ /************************************************************************/ #include<iostream> #include<vector> using namespace std; void printSequence(int *b,int* nums,int last); int main() { int nums[]={1,7,8,9,2,3,4,5}; //数组b存储在递增子序列中当前元素的前一个元素序号 int n = sizeof(nums) / sizeof(int); int *b=new int ; //vector容器last中存储各不同长度的递增子序列(同一长度的子序列,只考虑尾元素最小的序列) // 中最后一个元素的序号 vector<int> last; last.push_back(0); b[0]=0; for (int i=1;i<n;i++) { int low=0,high=last.size()-1; int middle=(low+high)/2; int pos; if(nums[i]>nums[last[high]]) {//如果当前元素比last中所有元素都大则最长递增子序列的长度加一,其尾元素为当前元素nums[i] last.push_back(i); b[i]=last[high]; }else{//否则使用二分法在last中查找到大于等于当前元素nums[i]的最小元素 while(low<high) { middle=(high+low)/2; if(nums[i]>nums[last[middle]]) low=middle+1; else high=middle-1; } //更新last中的元素值 if(nums[i]>nums[last[low]]) pos=low+1; else pos=low; last[pos]=i; b[i]=last[pos-1<0 ? 0 : pos-1]; } } cout<<"原序列长度为"<<n<<",如下:"<<endl; for (int i=0;i<n;i++) { cout<<nums[i]<<" "; } int len=last.size(); cout<<endl<<"最长递增子序列长度为"<<len<<",如下:"<<endl; printSequence(b,nums,last[len-1]); cout<<endl; delete[] b; return 0; } void printSequence(int *b,int* nums,int last) { if(b[last]!=last) printSequence(b,nums,b[last]); cout<<nums[last]<<" "; }
相关文章推荐
- 算法导论15.4-6:最长单调递增子序列
- 算法导论15.4-6 求一个n个数的序列的最长单调递增子序列 O(n*logn)
- 给定一个长度为N的数组,找出一个最长的单调自增子序列
- 给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱).
- 设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。
- 利用动态规划找出最长公共单调递增子序列
- 给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱). 第二解
- HD1160FatMouse's Speed(最长单调递增子序列)
- 最长单调递增子序列
- 最长单调递增子序列
- 最长单调递增子序列问题
- 最长单调递增子序列
- Longest Ordered Subsequence(最长单调递增子序列)poj2533+动态规划
- ACM最长单调递增子序列问题(动态规划)o(n*n)C++实现
- 最长单调递增子序列
- 51nod动态规化--最长单调递增子序列
- 动态规划题目一:最长单调递增子序列
- 最长单调递增子序列。
- 【DP】计算一个数组的最长递增子序列
- 最长单调递增子序列