代码随想录算法训练营第五十三天|1143.最长公共子序列、1035.不相交的线、718. 最大子序和

代码随想录算法训练营第五十三天|1143.最长公共子序列、1035.不相交的线、718. 最大子序和

最长公共子序列

1143.最长公共子序列
文章讲解:https://programmercarl.com/1143.%E6%9C%80%E9%95%BF%E5%85%AC%E5%85%B1%E5%AD%90%E5%BA%8F%E5%88%97.html
题目链接:https://leetcode.cn/problems/longest-common-subsequence/
视频讲解:https://www.bilibili.com/video/BV1ye4y1L7CQ/

自己看到题目的第一想法

和最长重复子数组的处理逻辑一样。dp[i][j]定义为0到i-1,0到j-1的最长公共子序列。

看完代码随想录之后的想法

这里的递推公式没有想明白,递推公式的第一个判断,nums[i-1]==nums[j-1]和最长重复子数组一样,都取dp[i][j] = dp[i-1][j-1] + 1。
但是当nums[i-1]!=nums[j-1]时,则取dp[i-1][j],dp[i][j-1]的最大值,dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]); 如给定 a b c d e;a c e;此时比到 abc和ace,发现c和e不相等,则取 abc和ac以及ab和ace的值的最大值。
这里的初始化值和最长重复子数组一样。

自己实现过程中遇到哪些困难

理解了思路,然后按照思路些代码还是简单的。

public int longestCommonSubsequence(String text1, String text2) {
    char[] text1Array = text1.toCharArray();
    char[] text2Array = text2.toCharArray();
    // 定义dp数组,2层循环,dp[i][j],以i为结尾的text1Array和以j为结尾的text2Array组成的最大公共子序列长度
    // 确定推导公式,前后有无递推 如果 text1Array[i] == text2Array[j],不是前一个相等了
    int[][] dp = new int[text1Array.length + 1][text2Array.length + 1];
// dp数组定义 dp[i][j]:用nums1的i-1位置为结尾以及nums2的j-1为结尾的最长子数组长度
int result = 0;
for(int i = 1; i <= text1Array.length; i++){
    for(int j = 1; j <= text2Array.length; j++){
        // 推导公式,如果每个数字的位数都相等,则长度加一
        if(text1Array[i - 1] == text2Array[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]);
        }
        result = Math.max(dp[i][j],result);
    }
}
return result;
}

不相交的线

1035.不相交的线
文章讲解:https://programmercarl.com/1035.%E4%B8%8D%E7%9B%B8%E4%BA%A4%E7%9A%84%E7%BA%BF.html
题目链接:https://leetcode.cn/problems/uncrossed-lines/
视频讲解:https://www.bilibili.com/video/BV1h84y1x7MP/

自己看到题目的第一想法

// 不相交的线,满足顺序,但是可以不连续,题目处理的方法和最长公共子序列一致。
代码实现:

public int maxUncrossedLines(int[] nums1, int[] nums2) {
    // 不相交的线,满足顺序,但是可以不连续
    int[][] dp = new int[nums1.length + 1][nums2.length + 1];
    int result = Integer.MIN_VALUE;
    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]);
            }
            result = Math.max(result,dp[i][j]);
        }
    }
    return result;
}

看完代码随想录之后的想法

思路:
绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且直线不能相交!
直线不能相交,这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。

自己实现过程中遇到哪些困难

还是要理解题目中的类似之处。

最大子序和

53. 最大子序和
文章讲解:https://programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html
题目链接:https://leetcode.cn/problems/maximum-subarray/
视频讲解:https://www.bilibili.com/video/BV19V4y1F7b5/

自己看到题目的第一想法

dp数组定义:
dp[i]:以i结尾的0-i最大子序和。
递推公式:dp[i-1] >= 0 则dp[i] = dp[i - 1] + nums[i] 否则dp[i] = nums[i]
初始化值:dp[0] = nums[0];

看完代码随想录之后的想法

整体逻辑一样,将dp的取值直接使用Math.max(dp[i - 1] + nums[i], nums[i]);
也是将result的值初始化成了dp[0];

自己实现过程中遇到哪些困难

  1. 边界条件处理没做好。
  2. 第0位置的dp状态最大值取值遗漏了。
public int maxSubArray(int[] nums) {
   // 动态规划实现
   // dp数组定义:dp[i]:取0-i时的最大和的连续子数组
   // 确定递推,dp[i-1] >= 0 则dp[i] = dp[i - 1] + nums[i] 否则dp[i] = nums[i]
   // 初始化值,dp[0] = nums[0];
   int[] dp = new int[nums.length];
   dp[0] = nums[0];
   if(nums.length == 1)return nums[0];
   int result = dp[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];
       }
       result = Math.max(result,dp[i]);
   }
   return result;
}

今日收获&学习时长

1143.最长公共子序列、1035.不相交的线、718. 最大子序和
前面两道题的答案都是一样的,第二道题要理解不相交的概念就是顺序匹配。
第一题、第二题的核心思路是如果当前位相同则取前一位置的最大值+1。不是当前位的话取不相等时的2种状态的最大值 abcde ace,比较到abc和ace时取abc-ac和ab-ace的最大值。

最大子序和的话就是取前一位置+当前位置和当前nums的最大值。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值