一、题目描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
二、解题
动态规划
方法1:
dp[i]表示当前数字最长子序列的长度,
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length<0){
return 0;
}
//动态规划 使用双重循环
int length = nums.length;
//dp[i]表示当前数字最长子序列的长度
int[] dp = new int[length];
dp[0] = 1;
for(int i = 1;i<length;i++){
dp[i] = 1;
//从下标为0开始算
for(int j = 0;j<i;j++){
//若当前数字大于遍历的数字
if(nums[i]>nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
}
int res = 0;
for(int num : dp){
res = Math.max(num,res);
}
return res;
}
}
方法2 :二分查找
dp数组来保存最小子序列的序列值。(长度为 i 的最长上升子序列的末尾元素的最小值)
这题需要注意下标的判定,也就是索引的确定。
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length<0){
return 0;
}
//动态规划+二分法
//这里使用dp数组来保存最小子序列
int[] dp = new int[nums.length];
//dp数组的当前指针下标
int cur = 0;
for(int index = 0 ;index<nums.length;index++){
//当前值 使用二分查找来将当前值插入dp数组。
int num = nums[index];
//使用两个指针 左指针指向最低值 右指针指向cur值
int l = 0,h = cur;
while(l<h){
int mid = (l+h)/2;
//如果中间值小于当前值
if(dp[mid]<num){
l = mid+1;
}else{
//若中间值大于等于当前值 则在左侧查找
h = mid;
}
}
dp[l] = num;
if(cur == h){
cur++;
}
}
return cur;
}
}
举个例子: