最长递增子序列
2016-04-13 21:44
399 查看
这是一道经典的动态规划题
最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列。
设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为:
dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].
这样简单的复杂度为O(n^2),其实还有更好的方法。
http://yzmduncan.iteye.com/blog/1546503 http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/
考虑两个数a[x]和a[y],x<y且a[x]<a[y],且dp[x]=dp[y],当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y],这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[t]一样时,尽量选择更小的a[x].
Our strategy determined by the following conditions,
1. If A[i] is smallest among all end candidates of active lists, we will start new active list of length 1.
2. If A[i] is largest among all end candidates of active lists, we will clone the largest active list, and extend it by A[i].
3. If A[i] is in between, we will find a list with largest end element that is smaller than A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list.
举个栗子
It will be clear with an example, let us take example from wiki {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
如果你对stl源码足够熟悉,binary_search函数可以用lower_bound()来代替。
所以简化版代码如下:
这里其实也用到了耐心排序的思想,可以看博客了解。http://www.cnblogs.com/kkun/archive/2011/11/23/2260291.html
最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列。
设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为:
dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].
int lengthOfLIS(vector<int>& nums) { int size = nums.size(); if(size ==0) return 0; vector<int> dp(size,1); for(int i = 1; i < size;i++){ for(int j = i-1; j >= 0 ;j--){ if(nums[i]>nums[j]){ dp[i] = max(dp[i],dp[j]+1); } } } int max_l = dp[0]; for(auto d : dp) max_l = max(max_l,dp); return max_l; }
这样简单的复杂度为O(n^2),其实还有更好的方法。
http://yzmduncan.iteye.com/blog/1546503 http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/
考虑两个数a[x]和a[y],x<y且a[x]<a[y],且dp[x]=dp[y],当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y],这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[t]一样时,尽量选择更小的a[x].
Our strategy determined by the following conditions,
1. If A[i] is smallest among all end candidates of active lists, we will start new active list of length 1.
2. If A[i] is largest among all end candidates of active lists, we will clone the largest active list, and extend it by A[i].
3. If A[i] is in between, we will find a list with largest end element that is smaller than A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list.
举个栗子
It will be clear with an example, let us take example from wiki {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
A[0] = 0. Case 1. There are no active lists, create one. 0. ----------------------------------------------------------------------------- A[1] = 8. Case 2. Clone and extend. 0. 0, 8. ----------------------------------------------------------------------------- A[2] = 4. Case 3. Clone, extend and discard. 0. 0, 4. 0, 8. Discarded ----------------------------------------------------------------------------- A[3] = 12. Case 2. Clone and extend. 0. 0, 4. 0, 4, 12. ----------------------------------------------------------------------------- A[4] = 2. Case 3. Clone, extend and discard. 0. 0, 2. 0, 4. Discarded. 0, 4, 12. ----------------------------------------------------------------------------- A[5] = 10. Case 3. Clone, extend and discard. 0. 0, 2. 0, 2, 10. 0, 4, 12. Discarded. ----------------------------------------------------------------------------- A[6] = 6. Case 3. Clone, extend and discard. 0. 0, 2. 0, 2, 6. 0, 2, 10. Discarded. ----------------------------------------------------------------------------- A[7] = 14. Case 2. Clone and extend. 0. 0, 2. 0, 2, 6. 0, 2, 6, 14. ----------------------------------------------------------------------------- A[8] = 1. Case 3. Clone, extend and discard. 0. 0, 1. 0, 2. Discarded. 0, 2, 6. 0, 2, 6, 14. ----------------------------------------------------------------------------- A[9] = 9. Case 3. Clone, extend and discard. 0. 0, 1. 0, 2, 6. 0, 2, 6, 9. 0, 2, 6, 14. Discarded. ----------------------------------------------------------------------------- A[10] = 5. Case 3. Clone, extend and discard. 0. 0, 1. 0, 1, 5. 0, 2, 6. Discarded. 0, 2, 6, 9. ----------------------------------------------------------------------------- A[11] = 13. Case 2. Clone and extend. 0. 0, 1. 0, 1, 5. 0, 2, 6, 9. 0, 2, 6, 9, 13. ----------------------------------------------------------------------------- A[12] = 3. Case 3. Clone, extend and discard. 0. 0, 1. 0, 1, 3. 0, 1, 5. Discarded. 0, 2, 6, 9. 0, 2, 6, 9, 13. ----------------------------------------------------------------------------- A[13] = 11. Case 3. Clone, extend and discard. 0. 0, 1. 0, 1, 3. 0, 2, 6, 9. 0, 2, 6, 9, 11. 0, 2, 6, 9, 13. Discarded. ----------------------------------------------------------------------------- A[14] = 7. Case 3. Clone, extend and discard. 0. 0, 1. 0, 1, 3. 0, 1, 3, 7. 0, 2, 6, 9. Discarded. 0, 2, 6, 9, 11. ---------------------------------------------------------------------------- A[15] = 15. Case 2. Clone and extend. 0. 0, 1. 0, 1, 3. 0, 1, 3, 7. 0, 2, 6, 9, 11. 0, 2, 6, 9, 11, 15. <-- LIS List ---------------------------------------------------------------------------- 所以代码如下
int binary_search(vector<int>& result, int start,int end,int target){ while(start < end-1){ int mid = (start+end)>>1; if(result[mid] >= target) end = mid ; else start = mid; } return end; } int lengthOfLIS(vector<int>& nums){ if(nums.empty()) return 0; vector<int> result; result.push_back(nums[0]); for(int i = 1; i < nums.size();i++){ if(nums[i] < result[0]) result[0] = nums[i]; else if(nums[i] > result.back()) result.push_back(nums[i]); else{ int index = binary_search(result,0,result.size()-1,nums[i]); result[index] = nums[i]; } } return result.size(); }
如果你对stl源码足够熟悉,binary_search函数可以用lower_bound()来代替。
所以简化版代码如下:
int lengthOfLIS(vector<int>& nums) { vector<int> res; for(int i=0; i<nums.size(); i++) { auto it = std::lower_bound(res.begin(), res.end(), nums[i]); if(it==res.end()) res.push_back(nums[i]); else *it = nums[i]; } return res.size(); }
这里其实也用到了耐心排序的思想,可以看博客了解。http://www.cnblogs.com/kkun/archive/2011/11/23/2260291.html
相关文章推荐
- 面试题82:一句先递增打印再递减打印
- c++ locale类
- 【POJ2280】Amphiphilic Carbon Molecules——扫描线
- 【c语言】编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间
- codeforces_455B
- Access转成Sql 2008步骤,同时解决自动编号问题,主键,id数值不重置
- 虚拟机类的加载过程
- java 树递归
- java8新语法学习
- JDK安装与环境变量配置
- 线段树 2016.4.15
- Golang实现ping
- sleep()方法和yield()方法的区别
- 【c语言】一个字符串,包含n个字符。将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。
- poj_1236_Network of Schools
- 软件工程_6th weeks
- (java)从零开始之--异常处理(以文件拷贝为例)
- Java中的XML
- HDU1171(01背包)
- CountDownLatch