LCS问题

基本思想:

  最长递增子序列问题原本是动态规划的经典问题,由于这个问题太经典了,所以我把它单独列在基本算法中。最简单的方法是动态规划,用一个数组dp[i]表示以nums[i]结尾的最长递增子序列的长度,对于每个dp[i],遍历dp[k](k<i),在所有nums[k] < nums[i]的元素中找到最大的dp[k]加1就是dp[i],时间复杂度为O(n2)。

 1 class Solution {
 2 public:
 3     int lengthOfLIS(vector<int>& nums) {
 4         if(nums.size() == 0) return 0;
 5         vector<int> dp(nums.size(),1);
 6         for(int i = 1;i != nums.size();++i){
 7             for(int j = 0;j != i;++j){
 8                 if(nums[i] > nums[j])
 9                     dp[i] = max(dp[i],dp[j]+1);
10             }
11         }
12         int result = 0;
13         for(int i = 0;i != dp.size();++i)
14             result = max(result,dp[i]);
15         return result;
16     }
17 };

  当然如果只是这种解法的话我也不写这篇随笔了,这道题还有一种O(nlogn)的解法,以Leetcode 300的例子为例,给一个数组[10,9,2,5,3,7,101,18],我们维护一个lastelem数组,lastelem[i]=t表示长度为i+1的子序列的第i个元素的最小值为t。有点抽象,那就模拟一下这个例子的解答。

1. [10,9,2,5,3,7,101,18]

         ^

  lastelem = [10]

2. [10,9,2,5,3,7,101,18]

              ^

  lastelem = [9]  //找到地一个比9大的数将其替换为9

3. [10,9,2,5,3,7,101,18]

                  ^

  lastelem = [2]  //同上

4. [10,9,2,5,3,7,101,18]

                      ^

  lastelem = [2,5]  //若5比最后一个数大,新填一个元素

5. [10,9,2,5,3,7,101,18]

                          ^

  lastelem = [2,3]  //同第二步

6. [10,9,2,5,3,7,101,18]

                              ^

  lastelem = [2,3,7]  //同第四步

7. [10,9,2,5,3,7,101,18]

                                    ^

  lastelem = [2,3,7,101]  //同第四步

8. [10,9,2,5,3,7,101,18]

                                           ^

  lastelem = [2,3,7,18]  //同第二步

  所以最终最长子序列的长度为lastelem数组的长度,即4,寻找第一个比nums[i]大的数可以用二分法,所以时间复杂度为O(nlogn). 此题是Leetcode 300原题,因为是基础题型,所以不再写博客解释了。

 1 class Solution {
 2 public:
 3     int lengthOfLIS(vector<int>& nums) {
 4         vector<int> lastelem;
 5         for(int i = 0;i != nums.size();++i){
 6             if(lastelem.empty() || nums[i] > lastelem.back())
 7                 lastelem.push_back(nums[i]);
 8             else{
 9                 int start = 0;
10                 int end = lastelem.size()-1;
11                 while(start < end){
12                     int pivot = start + (end-start)/2;
13                     if(lastelem[pivot] < nums[i])
14                         start = pivot+1;
15                     else
16                         end = pivot;
17                 }
18                 lastelem[start] = nums[i];
19             }
20         }
21         return lastelem.size();
22     }
23 };

 

posted on 2019-01-10 06:51  周浩炜  阅读(891)  评论(0编辑  收藏  举报

导航