【代码随想录】【动态规划】子序列问题 - 连续、不连续

在这里插入图片描述

子序列(不连续)

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. 不相交的线

1143. 最长公共子序列

子序列(连续)

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值