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?
算法一,动态规划
O(n*n) 在leetcode上实际执行时间为188ms
从左到右依次确定每个元素的LIS。
在确定当前元素的LIS,需要与左面的元素依次作比较:
如果左面的元素小于当前元素,则当前元素的LIS为左面的元素LIS+1;相等,则LIS与之相等。
取其最大值为当前元素的LIS值。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> lengths(nums.size(), 1);
int max_length = 0;
for (size_t i=0; i<nums.size(); ++i) {
for (int j=i-1; j>=0; --j) {
if (nums[j] < nums[i])
lengths[i] = max(lengths[i], lengths[j]+1);
else if (nums[j] == nums[i])
lengths[i] = max(lengths[i], lengths[j]);
}
max_length = max(max_length, lengths[i]);
}
return max_length;
}
};
算法二,
O(n log n), 在leetcode上执行时间为4ms。
维持一个潜在的LIS队列,
在队列中进行折半查找。找到满足>=当前值,队列中最小元素。即左边界。执行替换。
注意,这个队列,并不一定是合法的LIS。
但长度一定是对的,而且最后一个元素也是对的。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> seq;
for (auto i: nums) {
auto iter = lower_bound(seq.begin(), seq.end(), i);
if (iter == seq.end())
seq.push_back(i);
else
*iter = i;
}
return seq.size();
}
};
算法来源:
http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/