問題描述:
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?
源碼:
這題的tag是動態規劃,我就不展示其他的做法,直接上動態規劃。
首先看一下我自己的菜雞思路,我用dp[i]表示以i爲結尾的最長的遞增序列長度(必須包含元素i)。那麼遞歸方程可以寫成如下格式:
dp[i] = max(dp[j]+1) ,其中j<i且nums[i]>nums[j]
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size(), result = 1;
if (n==0) return 0;
vector<int> dp(n, 1);
for (int i=1; i<n; i++){
int tmp = 1;
for (int j=0; j<i; j++){
if (nums[j]<nums[i]){
tmp = max(tmp, dp[j] + 1);
}
}
dp[i] = tmp;
result = max(result, tmp);
}
return result;
}
};
看了一下solution有個基於二分查找的方法,英文的我也沒大看懂,還是翻了一下別人的博客。
dp[i]: 長度爲i + 1的上升子列的結尾元素的最小值
遍歷nums的每個元素,逐個與dp數組比較,更新dp數組中的元素或增長dp數組
更新的算法是:對於nums中的元素target,找到dp中大於等於target的最小元素,更新之;若target大於dp中最後一個元素,則將target置於dp後面一個位置,並增長dp
最終dp數組的長度就是nums的最大上升子列的長度
易證dp是一個單調遞增數列,因此更新算法的查找過程可以用O(logn)的時間複雜度完成
時間95%,空間66%
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size(), result = 1;
if (n==0) return 0;
vector<int> dp;
dp.push_back(nums[0]);
for (int i=1; i<n; i++){
if (dp.back() < nums[i]){
dp.push_back(nums[i]);
}
else {
*lower_bound(dp.begin(), dp.end(), nums[i]) = nums[i];
}
}
return dp.size();
}
};
其中Low_bound就是找大於等於目標值的最小值的位置