题目
思路一:动态规划
- 状态: dp[i]表示以nums[i]结尾的最长上升子序列的长度,一定要包含nums[i]。
- 状态转移方程: 遍历这个数之前的数,如果nums[j]<nums[i],那么到nums[i]的最长上升子序列长度为dp[i]和dp[j]+1两者的最大值。
- 初始化: 将dp[i]全部初始化为1,因为最长上升子序列至少为1(该数本身).
- 输出: dp[i]中的最大值。
具体代码
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int dp[] = new int[nums.length];
for(int i = 0;i < nums.length;i++){
dp[i] = 1;
}
int max = 1;
for(int i = 1;i < nums.length;i++){
for(int j = 0;j < i;j++){
if(nums[j]<nums[i]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
max = Math.max(max,dp[i]);
}
return max;
}
}
时间复杂度:O(N^2)
空间复杂度:O(N)
思路二:
太trick了,想不到。。。
具体代码
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int arr[] = new int[nums.length];
arr[0] = nums[0];
int end = 0;
for(int i = 1;i < nums.length;i++){
if(nums[i]>arr[end]){
//如果比末尾数大,直接加入arr
arr[++end] = nums[i];
}else{
//二分查找,找到第一个比nums[i]大的数,将nums[i]替换该数的前一个数,这个方法不能有重复的数。
int left = 0;
int right = end;
while(left < right){
int mid = left + ((right - left)>>1);
if(arr[mid]<nums[i]){
left = mid+1;
}else{
right = mid;
}
}
arr[left] = nums[i];
}
}
return end+1;
}
}
时间复杂度:O(nlogn)
空间复杂度:O(N)