子序列(不连续)
300. 最长递增子序列
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
//dp[i]: 以nums[i]结尾的最长递增子序列的长度
int[] dp = new int[n];
// 最终结果:max{dp[i]}
// 初始化
dp[0] = 1;
int max = 1; // 记录dp[i]中的最大值
// 递推计算
for(int i = 1; i < n; i++){
/* 在计算dp[i]时:
* ① 可以接在之前的子序列之后
dp[i] = dp[k] + 1, 0 <= k < i, nums[k] < nums[i]
* ② 可以从nums[i]重新开始新的子序列 -> dp[i] = 1
* 在所有情况中取最大值:
dp[i] = max {
1,
{dp[k] + 1 | 0 <= k < i, nums[k] < nums[i]}
}
*/
dp[i] = 1;
for(int k = 0; k < i; k++){
if(nums[k] < nums[i]){
dp[i] = Math.max(dp[k] + 1, dp[i]);
}
}
if(dp[i] > max){
max = dp[i];
}
}
// 返回结果
return max;
}
}
1143. 最长公共子序列
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length(), n = text2.length();
// dp[i][j]: text1[0...i]和text2[0...j]的最长公共子序列的长度
int[][] dp = new int[m][n];
// 初始化: i = 0, j = 0
dp[0][0] = text1.charAt(0) == text2.charAt(0) ? 1 : 0;
// 初始化: i = 0, j = 1 -> n-1
for(int j = 1; j < n; j++){
dp[0][j] = text1.charAt(0) == text2.charAt(j) ? 1 : dp[0][j-1];
}
// 初始化: j = 0, i = 1 -> m-1
for(int i = 1; i < m; i++){
dp[i][0] = text1.charAt(i) == text2.charAt(0) ? 1 : dp[i-1][0];
}
// 递推计算
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[i][j] = text1.charAt(i) == text2.charAt(j) ? dp[i-1][j-1] + 1 : Math.max(dp[i-1][j], dp[i][j-1]);
}
}
// 返回结果
return dp[m-1][n-1];
}
}
1035. 不相交的线
子序列(连续)
674. 最长连续递增序列
这道题不是动态规划的题目,是滑动窗口的题目。
class Solution {
public int findLengthOfLCIS(int[] nums) {
int n = nums.length;
int left = 0, right = 0;
// 循环不变量:保证窗口[left...right]内的元素是严格递增的
int maxLen = Integer.MIN_VALUE;
while(right < n){
// 只要right指针的下一个位置的元素 比right指针指向的元素大,就向右移动right指针
while(right + 1 < n && nums[right + 1] > nums[right]){
right++;
}
maxLen = Math.max(maxLen, right - left + 1);
left = ++right;
}
return maxLen;
}
}
718. 最长重复子数组
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
// dp[i][j]: nums[0...i]和nums[0...j]的
// 以nums[i]和nums[j]结尾的
// 最长重复连续子数组的长度
int[][] dp = new int[n][m];
// 最终结果:所有dp[i][j]中的最大值
int maxLen = Integer.MIN_VALUE; // 用于记录所有dp[i][j]中的最大值
// 初始化第一行
for(int j = 0; j < m; j++){
dp[0][j] = (nums1[0] == nums2[j] ? 1 : 0);
maxLen = Math.max(maxLen, dp[0][j]);
}
// 初始化第一列
for(int i = 1; i < n; i++){
dp[i][0] = (nums1[i] == nums2[0] ? 1 : 0);
maxLen = Math.max(maxLen, dp[i][0]);
}
// 递推计算
for(int i = 1; i < n; i++){
for(int j = 1; j < m; j++){
/* 在计算dp[i][j]时:
* ① 如果nums1[i] != nums2[j]:dp[i][j] = 0
* ② 如果nums1[i] == nums2[j]:dp[i][j] = dp[i-1][j-1] + 1
*/
dp[i][j] = (nums1[i] == nums2[j] ? dp[i-1][j-1] + 1 : 0);
maxLen = Math.max(maxLen, dp[i][j]);
// System.out.println("i = "+i+", j = "+j+" : "+dp[i][j]);
}
}
// 返回结果
return maxLen;
}
}
53. 最大子数组和
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
// dp[i]: 以第i个数结尾的连续子数组的最大和
int[] dp = new int[n];
// 初始化
dp[0] = nums[0];
int max = dp[0]; // 记录dp[i]的最大值
// 递推计算
for(int i = 1; i < n; i++){
dp[i] = Math.max(
dp[i-1] + nums[i], // 将nums[i]接在dp[i-1]之后
nums[i] // 从nums[i]重新开始
);
if(dp[i] > max) max = dp[i];
}
// 返回结果
return max;
}
}