算法训练day51-动态规划-最长公共子序列、不相交的线、最大子序和

1143.最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

示例 1:

输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace",它的长度为 3。

解题思路

  1. 确定dp数组下标及含义

dp[i][j]:表示test1[0,i-1]与test2[0,j-1]的最长公共子序列为dp[i][j]. 之所以是i-1、j-1是为了方便初始化。

  1. 确定递推公式

情况一:test1[i-1] == test2[j-1]

dp[i][j]是由dp[i-1][j-1] +1 得来的,所以:dp[i][j] = dp[i-1][j-1] + 1;

情况二:test1[i-1]!=test2[j-1]

那么dp[i][j] 可取dp[i-1][j] 或者 dp[i][j-1] 中的最大值

所以dp[i][j] =max( dp[i-1][j],dp[i][j-1]);

3.dp数组初始化

dp[i][0] = 0;

dp[0][j] = 0;

代码示例-java

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
       // 定义dp数组
       int[][] dp = new int[text1.length()+1][text2.length()+1];
       for(int i=1;i<=text1.length();i++){
           for(int j=1;j<=text2.length();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[text1.length()][text2.length()];
    }
}

1035.不相交的线

我们在两条独立的水平线上按给定的顺序写下 A 和 B 中的整数。

现在,我们可以绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且我们绘制的直线不与任何其他连线(非水平线)相交。

以这种方法绘制线条,并返回我们可以绘制的最大连线数。

解题思路

要找出A、B中相同的元素连线,并且要求连续不能相交的最大条数,那么可以看做求A、B中的最长公共子序列。那么其实现与上题1143.最长公共子序列 几乎一样。

代码示例-java

class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
       // 定义dp数组
       int[][]  dp = new int[nums1.length+1][nums2.length+1];
       for(int i=1;i<=nums1.length;i++){
           for(int j=1;j<=nums2.length;j++){
               if(nums1[i-1] == nums2[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[nums1.length][nums2.length];
    }
}

53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例: 输入: [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

解题思路

动态规划法:

  1. 确定dp数组下标及含义

dp[i] : 以nums[i] 为结尾的子数组最大和为 dp[i]

  1. 确定递推公式

一、dp[i] 可由dp[i-1]+nums[i]得来,即:dp[i] = dp[i-1] + nums[i]

二、dp[i] 是子数组的第一个元素,即: dp[i] = nums[i]

  1. 初始化

根据递推公式需要:dp[0] = nums[0]

  1. 遍历顺序

i从小到大

贪心法:

定义两个全局变量,分别记录当前区间和count(初始为0),和最大区间和sum(初始为最小整数)

从前向后遍历,不断累加元素到count上,并且比较count和sum ,将最大值赋给sum.

然后对于count一旦小于零,就重置为0,相当于重置了区间开头。最终得到的sum就是最大的。

代码示例-java

动态规划

class Solution {
    public int maxSubArray(int[] nums) {
      // 定义dp数组
      int[] dp = new int[nums.length];
      // 初始化
      dp[0] = nums[0];
      // 遍历
      int res = dp[0];
      for(int i=1;i<nums.length;i++){
          dp[i] = Math.max(dp[i-1] + nums[i] ,nums[i]) ;
          res = Math.max(dp[i],res);
      }
      return res;
    }
}

贪心算法

class Solution {
    public int maxSubArray(int[] nums) {
      if(nums.length==1){
          return nums[0];
      }
      int count = 0;
      int sum = Integer.MIN_VALUE;
      for(int i=0;i<nums.length;i++){
         count+=nums[i];
         // 取区间累计的最大值,重置区间结束位置
         sum = Math.max(sum,count);
         // 当区间和小于等于0时,重置count。相当于重置区间起始位置
         if(count<=0){
             count = 0;
         }
      }
      return sum;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值