[力扣 718] [leetcode 718] 最长重复子数组 2021.9.25

题目描述

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。

示例:

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

提示:

1 <= len(A), len(B) <= 1000
0 <= A[i], B[i] < 100

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

583 类似
但是这个题目要求子序列是连续的。如果不连续则不能算。

dp递推公式中的意义

本题dp table意义

dp[i][j] 代表以终点为nums1[i] nums2[j]时候的最长公共子序列长度。
所以要以不同的i,j 为终点求一个最大的长度。

如果dp[i][j] 的意义为 nums[0-i] nums2[0-j] 时的最长公共子序列长度
那是否是意味着 dp[nums1.size()][nums2.size()] 就是我们要求的结果?
那是否有

if value_equal:
    XXX
else:
    dp[i][j] = std::max(dp[i][j-1], dp[i-1][j]);

这样的代码呢?🤔

583题的相似性

如果像 583 那样

if text1[i] == text2[j]:
    dp[i][j] = dp[i-1][j-1] + 1
else:
    dp[i][j] = max(dp[i-1][j], dp[i][j-1])

则代表着,不论什么情况下都可以使用前面的值进行状态转移。(使用前面的状态进行推导)

而使用前面的状态推导是有条件的, 那就是此次推导与前面的值有关

那当 nums1[j] != nums2[j] 的时候,就与前面的值没有关系了🤔

但是此题目有:

  1. 如果相等,则可以使用前面的值
  2. 如果不相等,则不能使用前面的值。所以在这里dp[i][j] = 0

主要还是要想明白dp table的意义。

代码

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        std::vector<std::vector<int>> dp(nums1.size() + 1, std::vector<int>(nums2.size() + 1, 0));

        for (int i = 1; i < nums1.size() + 1; i++) {
            for (int j = 1; j < nums2.size() + 1; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    // 如果相等,看前面的值是否相等。
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    // 如果不相等,则本i,j的最长公共序列为0
                    dp[i][j] = 0;
                }
            }
        }

        int max_val = 0;
        for (int i = 0; i <= nums1.size(); i++) {
            for (int j = 0; j <= nums2.size(); j++) {
                max_val = std::max(max_val, dp[i][j]);
            }
        }
        return max_val;
    }
};
posted @ 2021-09-25 14:01  zh30  阅读(46)  评论(0)    收藏  举报