动态规划-子序列

子序列是序列的一部分,元素可以不连续。

子串是字符串的一部分,必须连续。

求子序列的和、连续递增子序列都是经典的一维动态规划问题。

这一类题目都有差不多的思路,我们看案例。

案例1:有一个整数数组 nums ,请你找出一个具有最大和的连续子数组,返回其最大和。子数组是数组中的一个连续部分。

我们假设数组nums长度为n,定义dp[i]为以nums[i]结尾的连续子数组的和,接下来需要考虑dp[i]和dp[i-1]是什么关系?

显而易见,如果dp[i-1]是大于0的,那么

dp[i]=dp[i-1]+nums[i]

如果dp[i-1]<=0,那么nums[i]加上一个负数一定比自己还小,索性不如不加

dp[i]=nums[i]

这样我们就得到了动态转移方程,接下来上代码

public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        //定义dp[i]为以nums[i]结尾的子数组的和
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        //最大值未必以最后一个元素结尾,所有需要遍历所有dp元素
        int maxAns = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (dp[i - 1] > 0) {
                dp[i] = dp[i - 1] + nums[i];
            } else {
                dp[i] = nums[i];
            }
            if (dp[i] > maxAns) {
                maxAns = dp[i];
            }
        }

        return maxAns;
    }

案例2:有一个整数数组 nums ,找到其中最长严格递增子序列的长度。

大家记住,子序列可以是不连续的。

我们假设dp[i]是以nums[i]结尾的递增序列,那么dp[i]和dp[i-1]是什么关系呢?

这个需要分两种情况,如果nums[i]>nums[i-1],那么dp[i]就可以接在dp[i-1]后面,

dp[i]=dp[i-1]+1

因为子序列可以不连续,我们接不上nums[i-1]可以考虑下前面的元素能不能接上。

如果nums[i]>nums[i-2],dp[i]就能接在dp[i-2]后面,dp[i]=dp[i-2]+1

综上所述,dp[i]等于所有比nums[i]的nums[j]对应的dp[j]+1

动态转移方程:

dp[i]=max{dp[j]+1 :nums[i]>nums[j],0<j<i}

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
 int m = text1.length();
        int n = text2.length();
        int[][] dp = new int[m+1][n+1];
        
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (text1.charAt(i-1) == text2.charAt(j-1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        return dp[m ][n ];
    }
}

 

posted @ 2022-11-01 13:34  Mars.wang  阅读(55)  评论(0编辑  收藏  举报