题目:
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18]
,
The longest increasing subsequence is [2, 3, 7, 101]
, therefore the length is 4
. Note that 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、动态规划:设dp[i]表示已nums[i]结尾的最长子序列,则状态转移方程为:dp[i] = max(dp[j] + 1), j < i && nums[j] < nums[i]。因此,采用两种循环就可以搞定,时间复杂度是O(n^2),空间复杂度是O(n)。
2、二分查找:这是求解最长递增子序列的一个经典算法。我们在遍历数组元素过程中维护一个单调递增的子数组。每次遍历到一个新元素,就查找比它大的第一个元素,然后替换这一元素;如果单调递增子数组中的所有元素都比该元素小,则将该元素添加到递增子序列中,并更新长度。该算法的空间复杂度是O(n),时间复杂度是O(nlogn)。
代码:
1、动态规划:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size() == 0) {
return 0;
}
vector<int> dp(nums.size(), 1);
for(int i = 1; i < nums.size(); ++i) {
for(int j = 0; j < i; ++j) {
if((nums[j] < nums[i]) && (dp[i] < dp[j] + 1)) {
dp[i] = dp[j] + 1;
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
2、二分查找:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
//vector<int> parent(nums.size()); // In case we need reconstruct the LIS
vector<int> increasing_subarray(nums.size() + 1);
int length = 0;
for(int i = 0; i < nums.size(); ++i) {
int low = 1, high = length; // Binary search
while(low <= high) {
int mid = std::ceil((low + high) / 2);
if(nums[increasing_subarray[mid]] < nums[i]) {
low = mid + 1;
}
else {
high = mid - 1;
}
}
int pos = low;
//parent[i] = increasing_subarray[pos - 1]; // Update parent/previous element for LIS
increasing_subarray[pos] = i; // Replacing or append
if(pos > length) {
length = pos;
}
}
/*vector<int> LIS(nums.size()); // Generate LIS by traversing parent array
int k = increasing_subarray[length];
for(int j = length - 1; j >= 0; --j)
{
LIS[j] = nums[k];
k = parent[k];
}*/
return length;
}
};