LeetCode 300. Longest Increasing Subsequence

Given an unsorted array of integers, find the length of longest increasing subsequence.html

Example:c++

Input: Output: 4 
Explanation: The longest increasing subsequence is , therefore the length is . [10,9,2,5,3,7,101,18][2,3,7,101]4

Note: 数组

  • There may be more than one LIS combination, it is only necessary for you to return the length.
  • Your algorithm should run in O(n2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?spa

 

很是经典的一道动态规划题目,经常使用解法有两个.net

一、暴力搜索c++11

时间复杂度O(N^2),空间复杂度O(N),f[i]表示以num[i]结尾的上升子序列的长度,外层循环遍历整个序列,复杂度O(n),内层循环则从第一个数遍历到外层循环的数字(不含)为止,转移方程为f[i] = max(f[i],f[j]+1)代码以下:code

 1 class Solution {
 2 public:
 3     int lengthOfLIS(vector<int>& nums) {
 4         if (nums.size() == 0)
 5             return 0;
 6         vector<int> v;
 7         int len = 1;
 8         for (int i = 0; i < nums.size(); i++)
 9         {
10             v.push_back(1);
11             for (int j = 0; j < i; j++)    //这里的能够是小于,也能够是小于等于
12                 if (nums[j] < nums[i])    //这里根据题目状况,若是要求严格单调上升,就必须是小于,不然应该是小于等于
13                     v[i] = max(v[i], v[j]+1);
14             if (v[i] > len)
15                 len = v[i];
16                     
17         }
18         return len;
19     }
20 };

 

二、二分搜索htm

时间复杂度O(N*logN),空间复杂度O(N),咱们能够用一个数组,来记录当前已经造成的递增子序列,该数组必定是单调不减的,咱们所但愿的是末尾的数字尽可能小,这样才会使得更多的数字有机会加入进来。外层循环须要遍历整个序列,内层循环则利用有序性进行二分查找,找到该数字在咱们定义的数组中的位置,而后更新,最终返回该数组的长度便可,可是这么作要注意咱们只保证长度是正确的,不保证该数组是一个最长上升子序列。blog

代码以下:ip

 1 class Solution {
 2 public:
 3     int lengthOfLIS(vector<int>& nums) {
 4         if (nums.size() == 0)
 5             return 0;
 6         vector<int> res;
 7         res.push_back(nums[0]);
 8         for (int i = 0; i < nums.size(); i++)
 9         {
10             int left = 0, right = res.size()-1;
11             if (nums[i] > res.back())
12                 res.push_back(nums[i]);
13             else
14             {
15                 while (left < right)
16                 {
17                     int mid = (left + right) / 2;
18                     if (res[mid] < nums[i])
19                         left = mid + 1;
20                     else
21                         right = mid;
22                 }
23                 res[right] = nums[i];
24             }
25         }
26         return res.size();
27     }
28 };

 易错点:6,7行,能够利用c++11新特性写成 res{nums[0]},可是千万别错写成res(nums[0])

另外,这道题的细节方面也值得注意,17行能够用移位运算代替除法提高速度,19行和21行是变形的二分查找,由于右边界搜索的速度放慢了,right = mid 而不是right = mid-1,这么作个人理解是“二分查找容许找不到返回-1,而咱们这里必定会找到一个适合插入的位置,因此右边界搜索速度减慢”,固然你也许会问若是把左边界搜索速度放慢右边界不变能够吗?好比19行改成left = mid, 21行改成 rigth = mid - 1, 答案是不行,会陷入死循环,[10,9,2,5,3,7,101,18]就过不了。由于咱们须要构造的是一个右紧密序列,也就是容许mid落在right上。
还有,15行必须为小于号,而不是小于等于,由于那样会陷入死循环,细节不少,须要注意!

 

参考连接:

http://www.javashuo.com/article/p-tjbllqud-eg.html

http://www.cnblogs.com/grandyang/p/4938187.html

http://www.javashuo.com/article/p-kavmicpr-dy.html

http://www.javashuo.com/article/p-hqpbmfjn-ha.html

相关文章
相关标签/搜索