动态规划: 最长重复子数组

这篇博客讨论了一种使用动态规划算法解决寻找两个整数数组中最长公共子数组长度的问题。作者首先介绍了问题背景和示例,然后详细阐述了动态规划的解决方案,包括确定状态转移方程、初始化dp数组以及状态压缩。最后,提供了两种不同空间复杂度的代码实现,并解释了为何需要在遍历过程中不断更新最长长度记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最长重复子数组

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

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

Solution

与之前写过的最长公共子序列还是有所区别的,子数组类似于子串,都是连续的。子序列可以是不连续的(注意:可以是不连续的,连续的情况也算是子序列)。
看到求解最值问题,首先可以想到动态规划算法,因此在思考再三之后,有了下面的想法:


  • 确定dp Table的维度,因为有两个数组,可能存在两个维度上的变化,所以先使用二维数组。

  • 确定完维度,需要做的就是定义每一个状态的含义,对于本题,已经非常明确地说明需要求解最长公共子数组,那么能给出定义:dp[ i ][ j ]表示A数组索引范围为[ 0, i ],B数组索引范围为 [ 0, j ]的状态下最长公共子数组的长度 (要说为什么能够想到这个定义,笔者感觉真的就是经验之谈,动态规划的形式见得多了可能会更加自然地想到一些方案,总之就是尽量往 可能会变化的参数 上靠,比如本题,变化的量也很简单,就是单一索引的不同,那么状态转移的时候改变的也就是数组的索引)。

  • 得到了每个状态的定义,接下来要推导递推公式,也就是常说的状态转移方程,首先细看一个状态dp[ i ][ j ],如果此时 A[ i ] != B[ j ],那么对于 A[0 : i], B[0 : j]范围内肯定是没有公共子数组,将dp[ i ][ j ]置为 0,反之,若 A[ i ] == B[ j ],那么在A[0 : i], B[0 : j]范围内至少会有一个长度为1的公共子数组(刚发生比较的这两元素)。但是另一方面,若该数组前一个状态 dp[ i - 1][ j - 1]也就是索引范围在 [0 : i - 1] , [ 0 : j - 1]内可能也存在一定长度的公共子数组,因此可以将其拼接起来,总的情况就是:
    在这里插入图片描述

  • 初始化dp数组;在递推公式中了解到可能会使用dp[i - 1][ j - 1],因此在对索引0的位置需要提前维护,一种做法是先将dp[0][j]与dp[i][0]都通过手动比较进行初始化,还有一种方法是对dp数组多加一行一列,这样就防止了越界问题。

在完成以上步骤之后可以写出dp数组了,这里给出示例的dpTable。
dp table

Codes
class Solution {
   
   
public:
	int findLength(vector<int>& nums1, vector<int>& nums2) {
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nepu_bin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值