力扣-718最长重复子数组(dp)

力扣-718最长重复子数组

1、题目

给两个整数数组 nums1nums2 ,返回 两个数组中 公共的长度最长的子数组的长度 。

示例 1:

输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。

2、分析

  • 题目。由题目可知,我们要求得是两个数组中间最长的相同的一部分,这里我还是首先想到的是暴力,推一下确实暴力也能够进行推出来。但是我们要进一步看能不能进行优化,根据最长长度,我们可以联想到是不是可以使用dp动态规划,答案是可以的。

  • 1)二维dp推导。这里我们要推导,所以跟前一个状态有关,前一个状态是什么?那就是nums1[i - 1]和nums2[j - 1]相等,也就是前一个数是相等的,所以我们到当前这个数时就做长度+1操作。也就是dp[i]【j】=dp[i - 1]【j-1】+1。

    2)或者第二种想法,就是按图形来分析。两个数组,一个为列,一个为行,所以就对应的话,这个对应的十字交点相等,那么值就是左上角值+1,也就是dp[i]【j】=dp[i - 1]【j-1】+1。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HcCf14S8-1678845287470)(img/image-20230315093539882.png)]

  • dp边界。由于第一个数可能会相等,所以左上角必须有值也就是i-1与j-1得,所以长度要比nums数组多1。

  • 一维dp推导,由图像可知,后一行的数是前一行的数复制到下一行然后如果当前数前一个相等,就当前数为前面一个加1。也就是至于那一行的数有关,dp[j]=dp[j-1] + 1;

3、代码及注释

class Solution {
    
    
    public int findLength(int[] nums1, int[] nums2) {
    
    
        // 1.进行暴力遍历
        int max = 0;
        for (int i = 0; i < nums1.length; i++){
    
    
            int temp = 0;
            for (int j = 0; j < nums2.length; j++) {
    
    
                if (nums1[i] == nums2[j]){
    
    
                    temp++;
                    int k = i;
                    int m = j;
                    while(k + 1 < nums1.length && m + 1 < nums2.length && nums1[++k] == nums2[++m]){
    
    
                        temp++;
                    }
                    max = Math.max(max, temp);
                    temp = 0;
                }
            }
            
        }
        return max;

        // 2.二维dp
        int[][] dp = new int[nums1.length + 1][nums2.length + 1];
        int max = 0;
        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;
                    max = Math.max(max, dp[i][j]);
                }
            }
        }
        return max;

        // 3.一维dp
        int[] dp = new int[nums2.length + 1];
        int max = 0;
        for (int i = 1; i < nums1.length + 1; i++){
    
    
            for (int j = nums2.length; j > 0; j--){
    
    
                if (nums1[i - 1] == nums2[j - 1]){
    
    
                    dp[j] = dp[j - 1] + 1;
                }else{
    
    
                    // 每一次继承上一行的dp[j]值,如果相等,就会+1存max中,如果不相等,当前行刷新dp[j]值为0。
                    dp[j] = 0;
                }
                max = max > dp[j] ? max : dp[j];
            }
        }
        return max;

    }
}

4、练习

力扣题目练习:718. 最长重复子数组

猜你喜欢

转载自blog.csdn.net/qq_51326491/article/details/129545955