定义
代码实现
动态规划实现(dp)
点击查看代码
class Solution {
public int lengthOfLIS(int[] nums) {
int len = 0;
// dp的定义是,0-i位置最长递增子序列的长度
int[] dp = new int[nums.length];
for(int i = 0; i < nums.length; i++) {
// 自己的长度,1
dp[i] = 1;
// 遍历之前的所有数,找到一个比自己小的数j,加上0-j的最长子序列。
for(int j = 0; j < i; j++) {
if(nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
len = Math.max(len, dp[i]);
}
return len;
}
}
记录0-i之间的严格递增的序列
为什么使用这个序列,我们从dp实现可以看到,我们第二层for循环的主要目的是找到,小于num[i]的长度记录。那么我们就可以使用二分搜索的方式找到小于num[i]的数。
那么如何生成这个数组呢?
那么假设,我们有一个数组end[],它内部是单调递增的数组。- 查询一个数,查一个小于等于它的数,就能得到相应的效果【第二层for循环的目的】
- 更新数呢,我们要保证严格的递增,假设我们找到小于等于它的数。那么我应该更新吗?
-
- 由于我们希望得到的长度尽量长,所以,这里的单调递增数组里面的数尽量小是最好的。
原因如下:
【1,3,2,5,3】我们的递增数组会有几个阶段【1,3】-> 【1,2】-> 【1,2,5】-> 【1,2,3】在这个情况下,在第一阶段变成第二阶段的时候,2不替换3,那么到最后阶段的3的时候并不会进入这个数组中。
在这里2进来的时候,找到的是1,再下标+1,替换掉3。
而在5的时候,找到的是2,再下标+1,添加一个新的数。(这里有一个难以实现的事情,怎么判断是找到一个绝对大的数,还是一个等于的数,在最后面的数组中)
那么,现在,我们换一种思考方式,如果找的是大于等于查找数的最小值(即最左边的值),如果找到那就直接替换,保证整体最小,如果找不到那么现在这个数最大,直接添加一个新的数。
- 由于我们希望得到的长度尽量长,所以,这里的单调递增数组里面的数尽量小是最好的。
点击查看代码
public int bs(int[] end, int len, int target) {
int l = 0, r = len - 1;
int ans = -1;
while(l <= r) {
int m = l + ((r - l) >> 1);
if(end[m] >= target) {
r = m - 1;
ans = m;
} else {
l = m + 1;
}
}
return ans;
}
浙公网安备 33010602011771号