LeetCode每日一题之最长重复子序列

289 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

题目描述

image.png

题目分析

这道题目与最长连续递增子序列相差不多,唯一不同的就是该题是求两个不同数组的最长重复子序列(两个数组),但其实思路都是差不多,最长连续递增子序列和重复子序列都需要连续,也是中间有一个数字不相等就需要重新计算,由于是两个数组,所以需要两层循环,每次比较最长重复子序列的长度。

状态转移公式分析

1.dp 数组定义:
dp[i][j] 表示以i-1结尾的数组nums1,已j-1结尾的数组nums2的最长重复子序列的长度 ,如果表示已i,j结尾的最长重复子序列的长度, 就应该数组从后往前遍历,更加直观,因为要比较的就是nums1[i]和nums2[j],下面会给出两种代码,可以打印dp体会一下。
2.状态转移分析:
如果nums1[i] = nums2[j], 则dp[i][j] = dp[i-1][j-1] + 1;
如果nums1[i] != nums2[j], 则dp[j][j] = 0;
3.初始值定义:
如果两个数组的每个数字都不相同,那么重复子序列的长度应该为0,两个空数组的重复子序列的长度也应该为0,即dp[0][0] = 0
4.遍历顺序:
dp[i][j] 由dp[i-1][j-1]推导则从前往后遍历,由dp[i+1][j+1]则从后往前遍历

代码实现

//dp[i][j] = dp[i+1][j+1]+1:
var findLength = function (nums1, nums2) {
  if (nums2.length === 0 || nums1.length == 0) return 0
  const dp = Array.from(Array(nums1.length+1), () => Array(nums2.length+1).fill(0))  // 因为最开始时i=nums1.length,要访问dp[i+1][j+1],所以定义的dp长度要加1,

  let result = 0;
  for (let i = nums1.length-1; i >=0; i--) { // 
    for (let j = nums2.length - 1; j >=0 ; j--) {
      if (nums1[i] == nums2[j]) { // 最先比较数组最后一位
        dp[i][j] = dp[i+1][j+1] + 1
      }
      if (result < dp[i][j]) result = dp[i][j]
    }
  }
  console.log(dp)
  console.log(result)
  return result
};

// dp[i][j] = dp[i-1][j-1] + 1
var findLength = function (nums1, nums2) {
  if (nums2.length === 0 || nums1.length == 0) return 0
  const dp = Array.from(Array(nums1.length+1), () => Array(nums2.length+1).fill(0))

  let result = 0;
  for (let i = 1; i <=nums1.length; i++) {
    for (let j = 1; j <=nums2.length ; j++) {
      if (nums1[i-1] == nums2[j-1]) { // 首先比较nums1[0],nums2[0]
        dp[i][j] = dp[i-1][j-1] + 1
      }
      if (result < dp[i][j]) result = dp[i][j]
    }
  }
  console.log(result)
  console.log(dp)
  return result
};

结语

个人理解,不喜轻喷。