「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」
题目
给两个整数数组 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
解题思路
动态规划
首先我们可以考虑到公共子数组在A、B两个数组里都是连续的,当递推过程获取公共子数组长度时,都是需要前一个的公共子数组长度,而且还需要知道前一个在A、B数组中的位置,再来对比接下来的数字是否一样,一样长度就加一。因此我们就想到使用dp[i][j]来记录最长公共子序列长度,这样也记录了相同数字在A,B中的位置。但是存在一个问题,对于dp[0][j]和dp[i][0]是难以在递推过程中使用dp[-1][j]和dp[i][-1]推导来,也难以初始化。我们可以退而求其次,使用dp[i][j]记录为A[i:]和B[j:]最长公共前缀长度。
- dp[i][j]的定义
dp[i][j]表示A[i:]和B[j:]最长公共前缀长度
- 状态转移方程
A[i:]和B[j:]最长公共前缀长度dp[i][j]是由dp[i-1][j-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, 这个我们可以在初始化的时候就直接设置为0。
for (let i = 1; i <= la; i++) {
for (let j = 1; j <= lb; j++) {
if(nums1[i - 1] === nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
res = Math.max(dp[i][j],res);
}
}
}
- dp[i][j]的初始化
dp[0][j]和dp[i][0]其最长公共前缀长度一定是0, 初始化为0即可
- 确定遍历顺序
dp[i][j] 是dp[i-1][j-1]推导而来,那么遍历i,j一定是从前向后遍历。
因此我们可以在更新dp值的时候,对比比较,以此记录最长重复子数组长度
var findLength = function(nums1, nums2) {
let la = nums1.length;
let lb = nums2.length;
let dp = Array.from(Array(la + 1),() => Array(lb + 1).fill(0));
let res = 0;
for (let i = 1; i <= la; i++) {
for (let j = 1; j <= lb; j++) {
if(nums1[i - 1] === nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
res = Math.max(dp[i][j],res);
}
}
}
return res;
};