摘要
本文主要介绍了LeetCode动态规划的几个题目,包括300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组。
1、300.最长递增子序列
1.1 思路
1、为什么dp[i]是表示数组以nums[i]结尾的最长递增子序列的长度是dp[i]?
根据这种定义,状态转移方程也更容易理解。通常,
dp[i]可以根据dp[j],其中0 <= j < i且nums[j] < nums[i]来更新。这表示我们可以考虑是否将nums[i]添加到以nums[j]结尾的最长递增子序列中,以获得更长的递增子序列。
2、为什么需要双重遍历?外层遍历和内层遍历分别表示什么意思?
外层遍历: 外层遍历的目的是确定最长递增子序列中的一个元素,通常表示当前考虑的子序列的结束位置。外层循环逐步移动,每一步都考虑下一个元素是否可以包括在最长递增子序列中。
内层遍历: 内层遍历的目的是与之前的元素进行比较,以确定是否可以将当前元素添加到最长递增子序列中。内层循环通常用于更新动态规划状态,以便计算以当前元素结尾的最长递增子序列长度。
- dp数组以及下标的含义: dp[i]表示数组以nums[i]结尾的最长递增子序列的长度是dp[i]
- 递推公式: dp[i] = Math.max(dp[i], dp[j] + 1);
- dp数组如何初始化: Array.fill(dp, 1);
- dp数组遍历顺序: 双层遍历,从小到大
- 打印dp数组
1.2 代码
public int lengthOfLIS(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
Arrays.fill(dp, 1);
int res = 1;
for(int i=1; i<len; i++) {
for(int j=0; j<i; j++) {
if(nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
res = Math.max(res, dp[i]);
}
}
return res;
}
2、674. 最长连续递增序列
2.1 思路
1、为什么只需要一次遍历?
从数组的第二个元素开始进行遍历。对于每个元素
nums[i],检查它是否大于前一个元素nums[i-1]。如果是,dp[i] = dp[i-1] + 1,表示当前元素可以加入前一个递增子序列中,增加子序列的长度;否则,dp[i] = 1,表示重新开始一个新的连续递增子序列
- dp数组以及下标的含义: dp[i]表示数组以nums[i]结尾的连续最长递增子序列的长度是dp[i]
- 递推公式: dp[i] = dp[i-1] + 1;
- dp数组如何初始化: Array.fill(dp, 1);
- dp数组遍历顺序: 一次遍历,从小到大
- 打印dp数组
2.2 代码
public int findLengthOfLCIS(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
Arrays.fill(dp, 1);
int res = 1;
for(int i=1; i<len; i++) {
if(nums[i] > nums[i-1]) {
dp[i] = dp[i-1] + 1;
}
res = Math.max(res, dp[i]);
}
return res;
}
3、718. 最长重复子数组
3.1 思路
1、子数组和子序列的区别?
子数组是原数组中的一段连续元素,而子序列是原序列中的一些元素,它们不必连续出现。
2、递推公式的理解?如何推导出 dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1] + 1)?
- 如果
A[i] == B[j],那么我们可以在以A[i-1]和B[j-1]为结尾的最长重复子数组后面加上一个相同的元素A[i],从而使得最长重复子数组的长度加一,即dp[i][j] = dp[i-1][j-1] + 1。- 如果
A[i] != B[j],说明当前元素不相同,那么以A[i]和B[j]为结尾的最长重复子数组的长度就是0,即dp[i][j] = 0。
- dp数组以及下标的含义:
dp[i][j]表示数组以nums1[i], nums2[j]结尾长度最长的公共子数组的长度是dp[i][j] - 递推公式:
dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1] + 1) - dp数组如何初始化
- dp数组遍历顺序: 双层遍历,从小到大
- 打印dp数组
3.2 代码
public int findLength(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int[][] dp = new int[len1][len2];
int res = 0;
for(int i=0; i<len1; i++) {
for(int j=0; j<len2; j++) {
if(nums1[i] == nums2[j]) {
if(i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1] + 1);
}
}
res = Math.max(res, dp[i][j]);
}
}
return res;
}