LeetCode 300. Longest Increasing Subsequence
Posted 皇家大鹏鹏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 300. Longest Increasing Subsequence相关的知识,希望对你有一定的参考价值。
Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input:[10,9,2,5,3,7,101,18]
Output: 4 Explanation: The longest increasing subsequence is[2,3,7,101]
, therefore the length is4
.
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?
非常经典的一道动态规划题目,常用解法有两个
1、暴力搜索
时间复杂度O(N^2),空间复杂度O(N),f[i]表示以num[i]结尾的上升子序列的长度,外层循环遍历整个序列,复杂度O(n),内层循环则从第一个数遍历到外层循环的数字(不含)为止,转移方程为f[i] = max(f[i],f[j]+1)代码如下:
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 };
2、二分搜索
时间复杂度O(N*logN),空间复杂度O(N),我们可以用一个数组,来记录当前已经形成的递增子序列,该数组一定是单调不减的,我们所希望的是末尾的数字尽量小,这样才会使得更多的数字有机会加入进来。外层循环需要遍历整个序列,内层循环则利用有序性进行二分查找,找到该数字在我们定义的数组中的位置,然后更新,最终返回该数组的长度即可,但是这么做要注意我们只保证长度是正确的,不保证该数组是一个最长上升子序列。
代码如下:
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行必须为小于号,而不是小于等于,因为那样会陷入死循环,细节很多,需要注意!
参考链接:
https://www.cnblogs.com/lsgxeva/p/7787245.html
http://www.cnblogs.com/grandyang/p/4938187.html
https://www.cnblogs.com/GodA/p/5180560.html
https://blog.csdn.net/George__Yu/article/details/75896330
以上是关于LeetCode 300. Longest Increasing Subsequence的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 300. Longest Increasing Subsequence
LeetCode 300. Longest Increasing Subsequence
LeetCode 300. Longest Increasing Subsequence
leetcode300.Longest Increasing Subsequence