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

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 代码随想录算法训练营第五十二天 | LeetCode 300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

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

文章链接:最长递增子序列最长连续递增序列最长重复子数组

视频链接:最长递增子序列最长连续递增序列最长重复子数组

1. LeetCode 300. 最长递增子序列

1.1 思路

  1. 本题是属于子序列系列,同样是动态规划解决的经典的一系列问题。
  2. dp 数组及其下标的含义:dp[i] 表示以 nums[i] 为结尾的最长递增子序列的长度为 dp[i]
  3. 递推公式:设 j 在 [0,i)之间,当 nums[i]>nums[j] 时,nums[i] 可以接在 nums[j] 之后(严格递增时),就相当于 nums[i] 是直接加在 dp[j] 原来的递增子序列后的,此时 dp[i]=dp[j]+1;当 nums[i]<=nums[j] 时,nums[i] 不可以接在 nums[j] 之后,就 dp[i]=dp[i]。因此 dp[i]=Math.max(dp[i],dp[j]+1)
  4. dp 数组的初始化:dp[i] 至少都是 1,意思是至少包含 nums[i]
  5. 遍历顺序:这里都依赖前面的元素,因此 i 一定是从左到右遍历,for(int i=1;i<nums.length;i++)为什么从 1 开始?因为 dp[0]=1 没必要求了,肯定为 1。for(int j=0;j<i;j++)遍历所有 nums[j] 的情况和 nums[i] 做比较,j 从前往后还是从后往前呢?其实都可以,只要把 [0,i) 之间都遍历了就可以了。if(nums[i]>nums[j])dp[i]=Math.max(dp[i],dp[j]+1)
  6. 最终结果存在哪呢?是在 dp 数组的最大值,就遍历 dp 数组,result=Math.max(dp[i],result),最终返回 result 即可
  7. 打印 dp 数组:用于 debug

1.2 代码

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

2. LeetCode 674. 最长连续递增序列

2.1 思路

  1. 本题和300. 最长递增子序列的区别就在于要求连续。
  2. dp 数组及其下标的含义:dp 表示以 i 为结尾的最长连续递增子序列为 dp[i]
  3. 递推公式:因为本题要求连续,就不需要比较前面所有的元素了,直接比较 nums[i] 和 nums[i-1],如果 nums[i]>nums[i-1] 就 dp[i]=dp[i-1]+1,就相当于 nums[i] 直接接在了 dp[i-1] 后面了,因此就 dp[i-1]+1
  4. dp 数组的初始化:dp 数组全部都初始化为 1,因为每个元素本身就是连续的,就是 1
  5. 遍历顺序:因为 i 依赖 i-1,因此是从前往后遍历,for(int i=1;i<nums.length;i++)这里为什么从 1 开始?因为 dp[0] 一定是 1。
  6. 最终结果在哪里?是在 dp 数组的最大值中,因此遍历 dp 数组,result=Math.max(dp[i],result),最终返回 result
  7. 打印 dp 数组:用于 debug

2.2 代码

/**
     * 1.dp[i] 代表当前下标最大连续值
     * 2.递推公式 if(nums[i+1]>nums[i]) dp[i+1] = dp[i]+1
     * 3.初始化 都为1
     * 4.遍历方向,从其那往后
     * 5.结果推导 。。。。
     * @param nums
     * @return
     */
    public static int findLengthOfLCIS(int[] nums) {
        int[] dp = new int[nums.length];
        for (int i = 0; i < dp.length; i++) {
            dp[i] = 1;
        }
        int res = 1;
  //可以注意到,這邊的 i 是從 0 開始,所以會出現和卡哥的C++ code有差異的地方,在一些地方會看到有 i + 1 的偏移。
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i + 1] > nums[i]) {
                dp[i + 1] = dp[i] + 1;
            }
            res = res > dp[i + 1] ? res : dp[i + 1];
        }
        return res;
    }

3. LeetCode 718. 最长重复子数组

3.1 思路

  1. 求两个数组的最长重复子数组的长度,其实就是求最长连续子序列。
  2. dp 数组及其下标的含义:我们用一个二维 dp 数组保存我们两个数组比较的状态。dp[i][j] 表示的是最长重复子数组,第一个数组到 i,第二个数组到 j,最长重复子数组为 dp[i][j]。即 dp[i][j] 表示以 i-1 为结尾的数组 1 和以 j-1 为结尾的数组 2,最长重复子数组长度为 dp[i][j]。为什么不以 i 和 j 为结尾呢?那么定义是为了简洁
  3. 递推公式:if(nums1[i-1]==nums2[j-1])就相当于找到两个数组中相等的元素了 dp[i][j]=dp[i-1][j-1]+1,为什么是从 i-1,j-1 这里+1 呢?因为我们是比较两个数组中的元素是否相同,如果相同就要两个数组一起往后退一格,一起看后面元素的状态,从这个
  4. dp 数组的初始化:dp[i][0] 和 dp[0][j] 就是第一列和第一行都是没有意义的状态,因为我们要用到 i-1 和 j-1,因此应该初始化为 0,因为 dp 数组是在前一个状态+1,这里没有意义就不要初始化为 1 了。其余位置会被递推公式覆盖,就可以不用初始化,默认为 0 即可
  5. 遍历顺序:肯定是两层 for 循环,先遍历数组 1 还是数组 2 呢?其实都可以。这里 for(int i=1;i<=nums1.length;i++)for(int j=1;j<=nums2.length;j++)因为 0 这一行和列没有意义,直接都从 1 开始。为什么取等于号呢?我们的 dp 数组的长度是 nums1 和 nums2 的长度加 1 的,而我们比较的时候是比较 nums[i-1] 和 nums[j-1],因此不会越界。
  6. 最终结果存在哪?不是在最后面的位置的,因此要遍历二维数组,找到最大值,因此在两层 for 循环遍历的时候就记录最大值了,再第二层 for 循环中最后 if(dp[i][j]>result)result=dp[i][j]
  7. 打印 dp 数组:用于 debug
  8. 解释:为什么不定义 i 和 j 为结尾的子序列呢?如果这样的话,第一列和第一行就要遍历统计,如果对应位置相等了,就要初始化为 1 了,就比较麻烦了

3.2 代码

// 版本一
class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int result = 0;
        int[][] dp = new int[nums1.length + 1][nums2.length + 1];
        for (int i = 1; i < nums1.length + 1; i++) {
            for (int j = 1; j < nums2.length + 1; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    result = Math.max(result, dp[i][j]);
                }
            }
        }
        return result;
    }
}
相关文章
|
10月前
|
存储 算法 调度
【复现】【遗传算法】考虑储能和可再生能源消纳责任制的售电公司购售电策略(Python代码实现)
【复现】【遗传算法】考虑储能和可再生能源消纳责任制的售电公司购售电策略(Python代码实现)
453 26
|
9月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
770 0
|
10月前
|
存储 编解码 算法
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
302 6
|
10月前
|
机器学习/深度学习 人工智能 搜索推荐
从零构建短视频推荐系统:双塔算法架构解析与代码实现
短视频推荐看似“读心”,实则依赖双塔推荐系统:用户塔与物品塔分别将行为与内容编码为向量,通过相似度匹配实现精准推送。本文解析其架构原理、技术实现与工程挑战,揭秘抖音等平台如何用AI抓住你的注意力。
2519 7
从零构建短视频推荐系统:双塔算法架构解析与代码实现
|
9月前
|
机器学习/深度学习 算法 机器人
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
393 8
|
9月前
|
机器学习/深度学习 算法 自动驾驶
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
456 8
|
10月前
|
机器学习/深度学习 传感器 算法
【高创新】基于优化的自适应差分导纳算法的改进最大功率点跟踪研究(Matlab代码实现)
【高创新】基于优化的自适应差分导纳算法的改进最大功率点跟踪研究(Matlab代码实现)
414 14
|
10月前
|
机器学习/深度学习 传感器 算法
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
626 2
|
9月前
|
存储 C++ 索引
最长连续序列(每天刷力扣hot100系列)
本题使用哈希表法求最长连续序列。利用unordered_set存储去重元素,遍历集合时仅当num-1不存在时才作为起点向后扩展,统计连续长度,时间复杂度O(n),空间复杂度O(n)。相比unordered_map更高效,因无需存储值。
|
10月前
|
canal 算法 vr&ar
【图像处理】基于电磁学优化算法的多阈值分割算法研究(Matlab代码实现)
【图像处理】基于电磁学优化算法的多阈值分割算法研究(Matlab代码实现)
264 1

热门文章

最新文章