题目
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明
- 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
- 你算法的时间复杂度应该为 O(n2) 。
思路一
- 动态规划。 d p [ i ] dp[i] dp[i]表示第i个数为结尾的最长上升子序列的长度。每次让j从0到i-1,找到每个nums[j] < nums[i]的数,然后取最大的 d p [ j ] + 1 dp[j]+1 dp[j]+1作为i处的最大上升子序列。
代码一
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if ( nums.size() == 0 ) return 0;
int ans = 1;
int size = nums.size();
vector<int> dp( size, 1 );
for ( int i = 1; i < size; ++i ) {
for ( int j = 0; j < i; ++j ) {
if ( nums[i] > nums[j] )
dp[i] = max( dp[i], dp[j] + 1 );
}
ans = max( ans, dp[i] );
}
return ans;
}
};
思路二
- 定义一个数字temp。遍历nums,对于每个元素n,如果大于temp的最后一个元素,则直接插入temp。如果小于,则使用二分查找,找到第一个大于n的数,将其替换为n。直到遍历完,temp的长度即为最长上升子序列的长度。
代码二
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if ( nums.size() == 0 ) return 0;
vector<int> temp;
temp.push_back( nums[0] );
for ( int i = 1; i < nums.size(); ++i ) {
if ( nums[i] > temp.back() )
temp.push_back( nums[i] );
else {
// 找到从左到右,第一个大于nums[i]的数
int left = 0;
int right = temp.size() - 1;
while ( left < right ) {
int mid = ( left + right ) >> 1;
if ( nums[i] <= temp[mid] )
right = mid;
else
left = mid + 1;
}
temp[left] = nums[i];
}
}
return temp.size();
}
};