力扣300. 最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
思路1、
用一个数组dp[i]代表前i个数字的最长上升序列,很显然
dp[0] = 1;
dp[i] = Math.max(dp[i],dp[j]+1),其中0<=j<i
代码如下:
class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length,max = 1;
if(len <= 1) return len;
int[] dp = new int[len];
dp[0] = 1;
for(int i = 1;i < len;i++){
dp[i] = 1;
for(int j = 0;j < i;j++){
if(nums[i] > nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
if(dp[i] > max) max = dp[i];
}
}
}
return max;
}
}方法二、dp+二分替换
实际上,我们遍历到的数a[i]只有两种情况
1、a[i]大于最大的数,直接插到dp数组的末位
2、a[i]小于等于最大的数,则替换掉对应的第一个比他大的。
至于第二种情况为什么这样处理,原因是这样的。
第一点,去覆盖掉不会影响所得到的子串的长度
第二点,可以通过替换掉,进行最小数"更新"
比如 1 7 8 2 3 4 5,模拟一下就懂了
代码如下:
class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length;
if(len <= 1) return len;
int[] dp = new int[len];
int pos = 0,max = 0;
for(int i = 0;i < len;i++){
pos = Arrays.binarySearch(dp,0,max,nums[i]);
if(pos < 0){
pos = -(pos + 1);
}
dp[pos] = nums[i];
if(pos == max){//新加入一个最大的数
max++;
}
}
return max;
}
}