将介绍动态规划(Dynamic Programming)在三道问题中的应用。问题分别是最长递增子序列(Longest Increasing Subsequence)、最长连续递增序列(Longest Continuous Increasing Subsequence)和最长重复子数组(Longest Common Subarray)。这些问题都可以使用动态规划的思想来解决,并且在时间复杂度方面具有很好的表现。
一、最长递增子序列
问题描述:给定一个未排序的整数序列,找到最长递增子序列的长度。
例如,给定 [10,9,2,5,3,7,101,18],最长递增子序列是 [2,3,7,101],因此长度是 4。
解题思路:我们可以使用动态规划的思想来解决这个问题。我们定义一个数组 dp[],其中 dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度。
首先,我们初始化 dp 数组的所有值为 1,因为每个元素本身都是一个递增子序列。然后,我们从第二个元素开始遍历整个数组。对于每个元素 nums[i],我们遍历其之前的所有元素 nums[j],如果 nums[i] 大于 nums[j],则说明 nums[i] 可以接在 nums[j] 后面形成一个更长的递增子序列。此时,我们更新 dp[i] 的值为 dp[j]+1 和 dp[i] 本身之间的较大值。
最终,我们遍历 dp 数组找到最大值,即为最长递增子序列的长度。
Java代码:
class Solution {
public int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0) return 0;
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
int max = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j]+1);
}
}
max = Math.max(max, dp[i]);
}
return max;
}
}
时间复杂度:O(n^2)
二、最长连续递增序列
问题描述:给定一个未排序的整数序列,找到最长连续递增序列的长度。
例如,给定 [1,3,5,4,7],最长连续递增序列是 [1,3,5],因此长度是 3。
解题思路:我们也可以使用动态规划的思想来解决这个问题。我们定义一个数组 dp[],其中 dp[i] 表示以 nums[i] 结尾的最长连续递增序列的长度。
首先,我们初始化 dp 数组的所有值为 1,因为每个元素本身都是一个连续递增序列。然后,我们从第二个元素开始遍历整个数组。对于每个元素 nums[i],如果 nums[i] 大于 nums[i-1],则说明 nums[i] 可以接在前一个元素后面形成一个更长的连续递增序列。此时,我们更新 dp[i] 的值为 dp[i-1]+1 和 dp[i] 本身之间的较大值。
最终,我们遍历 dp 数组找到最大值,即为最长连续递增序列的长度。
Java代码:
class Solution {
public int findLengthOfLCIS(int[] nums) {
if (nums == null || nums.length == 0) return 0;
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
int max = 1;
for (int i = 1; i < n; i++) {
if (nums[i] > nums[i-1]) {
dp[i] = dp[i-1]+1;
}
max = Math.max(max, dp[i]);
}
return max;
}
}
时间复杂度:O(n)
三、最长重复子数组
问题描述:给定两个整数数组 A 和 B,返回两个数组中公共的、长度最长的子数组的长度。
例如,给定 A=[1,2,3,2,1] 和 B=[3,2,1,4,7],最长重复子数组是 [3,2,1],因此长度是 3。
解题思路:我们也可以使用动态规划的思想来解决这个问题。我们定义一个二维数组 dp[][],其中 dp[i][j] 表示以 A[i-1] 和 B[j-1] 结尾的最长公共子数组的长度。
首先,我们初始化 dp 数组的第一行和第一列为 0,因为 A 或 B 中任意一个数组与空数组的最长公共子数组长度为 0。然后,我们从第二行第二列开始遍历 dp 数组。如果 A[i-1] 等于 B[j-1],则说明 A[i-1] 和 B[j-1] 可以接在它们之前的最长公共子数组后面形成一个更长的公共子数组。此时,我们更新 dp[i][j] 的值为 dp[i-1][j-1]+1 和 dp[i][j] 本身之间的较大值。
最终,我们遍历 dp 数组找到最大值,即为最长公共子数组的长度。
Java代码:
class Solution {
public int findLength(int[] A, int[] B) {
if (A == null || B == null || A.length == 0 || B.length == 0) return 0;
int m = A.length, n = B.length;
int[][] dp = new int[m+1][n+1];
int max = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (A[i-1] == B[j-1]) {
dp[i][j] = dp[i-1][j-1]+1;
max = Math.max(max, dp[i][j]);
}
}
}
return max;
}
}
时间复杂度:O(mn)
总结
本篇报告介绍了动态规划在三个问题中的应用,包括最长递增子序列、最长连续递增序列和最长公共子数组。这些问题都可以使用动态规划的思想来解决,并且在时间复杂度方面具有很好的表现。我们使用 Java 语言实现了这些算法,并分析了它们的时间复杂度。这些算法可以帮助我们更好地理解动态规划的思想,并且可以应用到实际问题中。