最长递增子序列

这是一道经典的动态规划题
最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数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

posted @ 2016-04-13 21:44  背锅侠  阅读(400)  评论(0编辑  收藏  举报