小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
来源:力扣(LeetCode)
代码
方法1
-
一维数组dp[i]表示以i作为结尾的递增子序列的值
-
遍历到dp[i]向前查找出nums[j]<nums[i]且这个dp[j]的值最大
class Solution {
public int lengthOfLIS(int[] nums) {
return lengthOfLISPus(nums);
}
public int lengthOfLIS1(int[] nums) {
int[] dp=new int[nums.length]; //dp[i]表示以i作为结尾的递增子序列的值
int longest=1;
dp[0]=1;
for(int i=1;i<nums.length;i++){
int j=i-1;
int leftMax=0;
while(j>=0){ //向前找
if(nums[j]<nums[i]){
leftMax=Math.max(leftMax,dp[j]); //更新
}
j--; //向前走
}
dp[i]=leftMax+1;
longest=Math.max(longest,dp[i]);
}
return longest;
}
方法2
在1的基础上加入一个一位数组ends[i]表示所有长度为i+1的递增子序列的最小
public int lengthOfLISPus(int[] nums) {
int[] dp = new int[nums.length]; //子序列必须以nums[i]最长递增子序列长度
int[] ends=new int[nums.length]; //ends[i]表示所有长度为i+1的递增子序列的最小结尾nums[i]
dp[0] = 1;
int index=0;
ends[index]=nums[0];
for (int i = 1; i <nums.length ; i++) {
int j=index;
while(j>=0){
//这个时候j指向最长的序列
if(nums[i]>ends[index]){
j++;
ends[j]=nums[i]; //更新ends[j+1]位置上的最小结尾
break;
}
j--; //j向前走
//找到ends[j]<nums[i],看看要不要更新
if(j>=0&&ends[j]<nums[i]){
//更新j
if(nums[i]<ends[j+1]){
ends[j+1]=nums[i];
}
break;
}
}
if(j<0&&ends[0]>nums[i]){
ends[0]=nums[i];
}
//更新index值,index指针指向有效区的位置
index=Math.max(index,j);
}
return index+1;
}
}