LeetCode 「中等」718.最长重复子数组

sankigan2025-3-11算法LeetCode

最长重复子数组open in new window

题目描述

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

示例

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

输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0]
输出:5

解答

暴力法

Code
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findLength = function(nums1, nums2) {
  const len1 = nums1.length;
  const len2 = nums2.length;
  let maxlen = 0;

  for (let i = 0; i < len1; ++i) {
    for (let j = 0; j < len2; ++j) {
      if (nums2[j] === nums1[i]) {
        let sublen = 1; // 公共序列长度至少为 1
        while (
          i + sublen < len1 &&
          j + sublen < len2 &&
          nums1[i + sublen] === nums2[j + sublen]
        ) {
          ++sublen; // 公共子序列长度每次增加 1,考察新的一项
        }
        maxlen = Math.max(maxlen, sublen);
      }
    }
  }

  return maxlen;
};

动态规划

思路

  1. 定义状态
  • 使用一个二维数组 dp,其中 dp[i][j] 表示 nums1 的前 i 和元素和 nums2 的前 j 个元素中,以 nums1[i - 1]nums2[j - 1] 结尾的最长公共子数组的长度
  1. 状态转移
  • 如果 nums1[i - 1] 等于 nums2[j - 1],则 dp[i][j] = dp[i - 1][j - 1] + 1
  • 如果 nums1[i - 1] 不等于 nums2[j - 1],则 dp[i][j] = 0
  1. 初始化
  • dp[0][j] = 0,因为 nums1 的前 0 个元素和 nums2 的前 j 个元素没有公共子数组
  • dp[i][0] = 0,因为 nums1 的前 i 个元素和 nums2 的前 0 个元素没有公共子数组
  1. 计算结果
  • 遍历 dp 数组,找到其中的最大值,即为两个数组中公共的、长度最长的子数组的长度
Code
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findLength = function(nums1, nums2) {
  const m = nums1.length;
  const n = nums2.length;
  // 定义一个数组 dp,大小为 (m + 1) * (n + 1),其中 m 和 n 分别是 nums1 和 nums2 的长度
  const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
  let maxlen = 0;

  for (let i = 1; i <= m; ++i) {
    for (let j = 1; j <= n; ++j) {
      if (nums1[i - 1] === nums2[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = 0;
      }

      maxlen = Math.max(maxlen, dp[i][j]);
    }
  }

  return maxlen;
}

降维优化

dp[i][j] 只依赖上一行上一列的对角线的值,所以我们从右上角开始计算。也就是沿着从右到左、从上到下的顺序遍历 dp 数组

Code
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findLength = function(nums1, nums2) {
  const m = nums1.length;
  const n = nums2.length;
  const dp = new Array(n + 1).fill(0);
  let maxlen = 0;

  for (let i = 1; i <= m; ++i) {
    for (let j = n; j >= 1; --j) {
      if (nums1[i - 1] === nums2[j - 1]) {
        dp[j] = dp[j - 1] + 1;
      } else {
        dp[j] = 0;
      }

      maxlen = Math.max(maxlen, dp[j]);
    }
  }

  return maxlen;
}
更新于 2025/3/12 15:40:41