算法-动态规划-最长递增子序列
1 题目概述
1.1 题目出处
https://leetcode.cn/problems/longest-increasing-subsequence/
1.2 题目描述
2 动态规划
2.1 思路
思考如果以dp[i]表示i位置的字符的最长递增子序列长度,那么很难找到dp[i]和dp[i-1]的关系,因为dp[i]没有携带是否取当前位置字符的信息。
那么我们以dp[i]表示以位置i结尾的字符的最长递增子序列长度,那么就可以找到dp[i]和dp[i-1]、dp[i-2] …的关系,只要nums[j] < nums[i],则j 和 i就能组成递增子序列 ,我们从i-1比较到0,取dp[j]最大值+1作为dp[i]的值即可。
2.2 代码
class Solution {
int result = 0;
public int lengthOfLIS(int[] nums) {
if (nums.length == 0) {
return result;
}
// 表示以指定位置结尾的最长递增子序列
int[] dp = new int[nums.length];
for (int i = 0; i < dp.length; i++) {
dp[i] = 1;
for (int j = i - 1; j >= 0; j--) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[j] + 1, dp[i]);
}
}
result = Math.max(result, dp[i]);
}
return result;
}
}
2.3 时间复杂度
O(N^2)
2.4 空间复杂度
O(N)
3 二分查找
3.1 思路
3.2 代码
class Solution {
public int lengthOfLIS(int[] nums) {
List<Integer> resultList = new ArrayList<>();
resultList.add(nums[0]);
for (int i = 1; i < nums.length; i++) {
int lastIndex = resultList.size() - 1;
if (nums[i] < resultList.get(lastIndex)) {
// 比当前子序列尾元素还小,需要替换放入合适位置
// 规则是替换掉resultList中最小的比当前元素nums[i]大的元素
int m = 0, n = lastIndex;
while (m < n) {
int mid = (m + n) / 2;
if (resultList.get(mid) < nums[i]) {
m = mid + 1;
} else if (resultList.get(mid) > nums[i]) {
n = mid - 1;
} else {
m = mid;
break;
}
}
if (nums[i] <= resultList.get(m)) {
resultList.set(m, nums[i]);
} else {
resultList.set(m + 1, nums[i]);
}
} else if (nums[i] > resultList.get(lastIndex)) {
// 直接加入上升序列
resultList.add(nums[i]);
}
}
return resultList.size();
}
}
3.3 时间复杂度
O(NlogN)
3.4 空间复杂度
O(K) K为最长子序列长度
参考文档
- https://leetcode.cn/problems/longest-increasing-subsequence/solutions/198897/chao-xiang-xi-tu-jie-di-gui-dong-tai-gui-hua-er-fe/
- https://leetcode.cn/problems/longest-increasing-subsequence/solutions/896590/yi-ti-shuang-jie-tu-jie-yuan-li-ji-chu-d-ptpz/
- 最全最长上升子序列类问题:LIS长度,一个LIS,LIS的个数,所有LIS