最长递增子序列
这是一道经典的动态规划题
最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数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].
1 int lengthOfLIS(vector<int>& nums) { 2 int size = nums.size(); 3 if(size ==0) return 0; 4 vector<int> dp(size,1); 5 for(int i = 1; i < size;i++){ 6 for(int j = i-1; j >= 0 ;j--){ 7 if(nums[i]>nums[j]){ 8 dp[i] = max(dp[i],dp[j]+1); 9 } 10 } 11 } 12 int max_l = dp[0]; 13 for(auto d : dp) 14 max_l = max(max_l,dp); 15 return max_l; 16 }
这样简单的复杂度为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 ----------------------------------------------------------------------------
所以代码如下
1 int binary_search(vector<int>& result, int start,int end,int target){ 2 while(start < end-1){ 3 int mid = (start+end)>>1; 4 if(result[mid] >= target) end = mid ; 5 else start = mid; 6 } 7 return end; 8 } 9 10 int lengthOfLIS(vector<int>& nums){ 11 if(nums.empty()) return 0; 12 vector<int> result; 13 result.push_back(nums[0]); 14 for(int i = 1; i < nums.size();i++){ 15 if(nums[i] < result[0]) result[0] = nums[i]; 16 else if(nums[i] > result.back()) result.push_back(nums[i]); 17 else{ 18 int index = binary_search(result,0,result.size()-1,nums[i]); 19 result[index] = nums[i]; 20 } 21 } 22 return result.size(); 23 }
如果你对stl源码足够熟悉,binary_search函数可以用lower_bound()来代替。
所以简化版代码如下:
1 int lengthOfLIS(vector<int>& nums) { 2 vector<int> res; 3 for(int i=0; i<nums.size(); i++) { 4 auto it = std::lower_bound(res.begin(), res.end(), nums[i]); 5 if(it==res.end()) res.push_back(nums[i]); 6 else *it = nums[i]; 7 } 8 return res.size(); 9 }
这里其实也用到了耐心排序的思想,可以看博客了解。http://www.cnblogs.com/kkun/archive/2011/11/23/2260291.html