代码随想录算法训练营第五十二天|300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

代码随想录算法训练营第五十二天|300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

最长递增子序列

300.最长递增子序列
文章讲解:https://programmercarl.com/0300.%E6%9C%80%E9%95%BF%E4%B8%8A%E5%8D%87%E5%AD%90%E5%BA%8F%E5%88%97.html
题目链接:https://leetcode.cn/problems/longest-increasing-subsequence/
视频讲解:https://www.bilibili.com/video/BV1ng411J7xP/

自己看到题目的第一想法

没想到好的处理方式。

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

列出一张图,如 10 9 2 5 3 7 21这个序列要求最长递增子序列。
在这里插入图片描述

  • 确定dp数组以及其下标含义
    • dp[i]:以nums[i]为结尾的最长连续子序列的长度。
  • 确定递推公式
    • 简单来说就是定义一个i和j,j从0遍历到i-1,然后dp[i]的最大值由j遍历从0到i-1的dp[j]最大值得到,如果nums[i] > nums[j],那dp[i]的最大值就是此刻遍历到的j的dp[j]+1。
  • 确定初始化值
    • 因为每个位置至少有一个自己的数字作为最大值,因此所有的dp[i]的初始值都为1
  • 确定遍历顺序
    • 因为大的值都是由前面小的值推导过来的,因此遍历顺序应该是从前到后
  • 打印数组

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

这道题还是相当难理解,后面手写推导了一次状态转移的逻辑就懂了。

public int lengthOfLIS(int[] nums) {
   int[] dp = new int[nums.length];
   Arrays.fill(dp,1);
   int result = dp[0];
   for(int i = 1; i < nums.length; i++){
       for(int j = 0; j < i; j++){
           if(nums[i] > nums[j]){
              dp[i] = Math.max(dp[i], dp[j] + 1);
           }
       }
       result = Math.max(result,dp[i]);
   }
   return result;
}

最长连续递增序列

674. 最长连续递增序列 
文章讲解:https://programmercarl.com/0674.%E6%9C%80%E9%95%BF%E8%BF%9E%E7%BB%AD%E9%80%92%E5%A2%9E%E5%BA%8F%E5%88%97.html
题目链接:https://leetcode.cn/problems/longest-continuous-increasing-subsequence/
视频讲解:https://www.bilibili.com/video/BV1bD4y1778v/

自己看到题目的第一想法

该题和上一题的区别就是本题是连续的。上一题不需要连续。连续和不连续的最大区别就是i只和小一位的j比较,如果比较失败直接为1。
自己写的代码,写完为了验证,还手动推导了一下:

public int findLengthOfLCIS(int[] nums) {
    int[] dp = new int[nums.length];
    Arrays.fill(dp,1);
    int result = dp[0];
    for(int i = 1; i < nums.length; i++){
        if(nums[i] > nums[i - 1]){
            dp[i] = dp[i - 1] + 1;
        }
        result = Math.max(result,dp[i]);
    }
    return result;
 }

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

这里和我想的一样,只需要比较nums[i]与nums[i - 1],而不用去比较nums[j]与nums[i] (j是在0到i之间遍历)。
既然不用j了,那么也不用两层for循环,一层for循环就行,比较nums[i] 和 nums[i - 1]。

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

最长重复子数组

718. 最长重复子数组
文章讲解:https://programmercarl.com/0718.%E6%9C%80%E9%95%BF%E9%87%8D%E5%A4%8D%E5%AD%90%E6%95%B0%E7%BB%84.html
题目链接:https://leetcode.cn/problems/maximum-length-of-repeated-subarray/
视频讲解:https://www.bilibili.com/video/BV178411H7hV/

自己看到题目的第一想法

暴力解法:
两层循环,外层是长度长一点的数组。然后循环遍历nums1,从nums2找到匹配的位置,匹配到了后一起开始向后移动,得到最大值。

动态规划,核心找到递推公式,动态规划五步骤:
dp数组定义:dp[i][j] i表示nums1[i]之前,j表示nums2[j]之前长度最长的子数组。dp[nums1.length -1][nums2.length - 1]就为子数组最长。
递推公式:动态规划没想出来

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

动态规划数组定义:

  • 和自己想的类似,dp[i][j]表示以i-1为尾的nums1和以j-1为尾的num2的最长重复子数组的长度。
  • 递推公式if(nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
  • 初始化值,如果这里用dp[i][j]用以i结尾的nums1和以j为尾的nums2的最长重复子数组的话就需要做两次遍历取dp[0][j],dp[i][0]。而这里用i-1,j-1则免去了计算初始值的流程,因为当i=0、j=0时,i-1,j-1无意义,所以直接初始化成0

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

dp数组的初始化大小以及循环遍历的次数没处理好,循环的终止条件应该为i <= nums1.length、j <= nums2.length,因为第0位是无意义的值,且比较的是**nums1[i - 1] == nums2[j - 1]**实际要取到nums1.length的位置才能遍历完所有的值。

public int findLength(int[] nums1, int[] nums2) {
    int[][] dp = new int[nums1.length + 1][nums2.length + 1];
    // dp数组定义 dp[i][j]:用nums1的i-1位置为结尾以及nums2的j-1为结尾的最长子数组长度
    int result = 0;
    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;
                result = Math.max(dp[i][j],result);
            }
        }
    }
    return result;
}

今日收获&学习时长

子序列问题这三题的关键是确定dp数组的定义,这个非常关键。
第一题最长递增子序列,dp数组的定义使用以nums[i]为结尾的最长连续子序列的长度来表示。然后再用j来表示0-i-1的最长子序列,若nums[i] > nums[j],则dp[i] = dp[j] + 1;
第二题最长连续递增子序列和第一题差不多,但是不需要做2次循环,只需要做一次循环然后和i-1比较即可。
第三题最长重复子数组,这道题的核心也是确定dp数组定义,和上面题目差不多,都是用取nums[i],取nums[j]为结尾做dp数组定义。然后再根据题目要义,连续子数组来做匹配。

整体耗时较长,但是都理解了题目。后续二刷

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值