LeetCode 718 - 最长重复子数组

LeetCode 718 - 最长重复子数组 是一个典型的数组和字符串问题,适合考察动态规划、滑动窗口和二分查找等多种编程能力。掌握其多种解法及变体能够有效提高处理字符串和数组算法的能力。


题目描述

  • 输入: 两个整数数组 nums1nums2
  • 输出: 两个数组中存在的最长的连续重复子数组的长度。
  • 要求: 时间复杂度尽可能优化。

示例

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

解法分析及实现

解法 1:二维动态规划

思路
  • 定义 dp[i][j] 表示:
    • 以下标 i-1(对于 nums1)结尾的子数组和以下标 j-1(对于 nums2)结尾的子数组的最长公共子数组长度。
  • 状态转移方程:
    • 如果 nums1[i-1] == nums2[j-1]:
      dp[i][j] = dp[i-1][j-1] + 1
      
    • 否则:
      dp[i][j] = 0
      
  • 初始化:
    • dp[i][0] = 0 (空序列和任何序列无公共子数组)。
    • dp[0][j] = 0 (空序列和任何序列无公共子数组)。
  • 最终答案:
    • 遍历所有的 dp[i][j],取最大值。
模板代码
class Solution {public int findLength(int[] nums1, int[] nums2) {int m = nums1.length, n = nums2.length;int[][] dp = new int[m + 1][n + 1];int maxLength = 0;// 动态规划填表for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (nums1[i - 1] == nums2[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;maxLength = Math.max(maxLength, dp[i][j]);}}}return maxLength;}
}
复杂度分析
  • 时间复杂度: O(m * n),其中 mn 是数组长度。
  • 空间复杂度: O(m * n),由于用了二维 DP 表保存状态。

解法 2:滚动数组优化动态规划(空间优化)

优化思路
  • 注意到在计算 dp[i][j] 时,只需要用到 dp[i-1][j-1] 的值。因此,可以用一维数组代替二维数组,进一步优化空间。
  • 滚动更新:从右往左遍历 nums2,避免覆盖之前的状态。
模板代码
class Solution {public int findLength(int[] nums1, int[] nums2) {int m = nums1.length, n = nums2.length;int[] dp = new int[n + 1];int maxLength = 0;// 动态规划填表for (int i = 1; i <= m; i++) {for (int j = n; j >= 1; j--) { // 注意,从右往左遍历 nums2if (nums1[i - 1] == nums2[j - 1]) {dp[j] = dp[j - 1] + 1;maxLength = Math.max(maxLength, dp[j]);} else {dp[j] = 0; // 无法连续时,长度清零}}}return maxLength;}
}
复杂度分析
  • 时间复杂度: O(m * n),遍历数组。
  • 空间复杂度: O(n),使用了一维数组。

解法 3:滑动窗口法

核心思想
  • 假设固定一个数组 nums1,滑动另一个数组 nums2 进行比较。
  • 在滑动的过程中寻找最大公共子数组长度。
    • 如果 nums1nums2 不完全对齐,就逐步滑动 nums2,逐一比较。
模板代码
class Solution {private int maxLen(int[] A, int[] B, int offsetA, int offsetB, int length) {int maxLen = 0, currentLen = 0;for (int i = 0; i < length; i++) {if (A[offsetA + i] == B[offsetB + i]) {currentLen++;maxLen = Math.max(maxLen, currentLen);} else {currentLen = 0;}}return maxLen;}public int findLength(int[] nums1, int[] nums2) {int m = nums1.length, n = nums2.length;int maxLength = 0;// 滑动 nums1 相对于 nums2for (int i = 0; i < m; i++) {int len = Math.min(n, m - i); // 两数组能对齐的长度maxLength = Math.max(maxLength, maxLen(nums1, nums2, i, 0, len));}// 滑动 nums2 相对于 nums1for (int j = 0; j < n; j++) {int len = Math.min(m, n - j); // 两数组能对齐的长度maxLength = Math.max(maxLength, maxLen(nums1, nums2, 0, j, len));}return maxLength;}
}
复杂度分析
  • 时间复杂度: O((m + n) * min(m, n)),滑动两遍数组。
  • 空间复杂度: O(1),原地比较,不需要额外空间。

解法 4:二分查找 + 哈希

核心思想
  • 使用滑动窗口与哈希表结合,通过 二分查找 在所有可能的子数组长度中快速找到最长重复子数组长度。
    1. 利用暴力检查或 Rabin-Karp 哈希验证是否存在长度为 mid 的公共子数组:
      • 用窗口提取长度为 mid 的子数组,进行比对。
    2. 使用二分查找:
      • 如果某个长度是可行的(存在共同子数组),增加长度;
      • 如果不可行,减小长度。
模板代码
import java.util.HashSet;class Solution {public int findLength(int[] nums1, int[] nums2) {int left = 0, right = Math.min(nums1.length, nums2.length);int result = 0;while (left <= right) {int mid = left + (right - left) / 2;if (check(nums1, nums2, mid)) {result = mid;left = mid + 1; // 尝试更长的长度} else {right = mid - 1; // 尝试更短的长度}}return result;}private boolean check(int[] nums1, int[] nums2, int len) {// 使用 HashSet 存储 nums1 长度为 len 的子数组HashSet<String> seen = new HashSet<>();for (int i = 0; i + len <= nums1.length; i++) {seen.add(arrayToString(nums1, i, len));}// 检查 nums2 是否包含相同子数组for (int j = 0; j + len <= nums2.length; j++) {if (seen.contains(arrayToString(nums2, j, len))) {return true;}}return false;}private String arrayToString(int[] nums, int start, int len) {StringBuilder sb = new StringBuilder();for (int i = start; i < start + len; i++) {sb.append(nums[i]).append(",");}return sb.toString();}
}
复杂度分析
  • 时间复杂度: O(log(min(m, n)) * (m + n)),二分查找次数乘以每次滑动窗口检查的时间。
  • 空间复杂度: O(min(m, n)),为哈希表的空间。

变体问题

  1. 最长公共子序列 (LCS)

    • 两数组中非连续元素符合顺序的最长子序列长度。
    • DP 思路与本题类似,但不要求元素连续。
  2. 最长公共前缀 (Longest Common Prefix)

    • 但不局限于以何种顺序,重点是找最大前缀。
  3. 编辑距离问题

    • 在两个字符串之间,进行最少字符操作(包括插入、删除、替换)使其相等。
  4. 字符串匹配问题(KMP 或 Rabin Karp)

    • 查找两个字符串的最大匹配区段。

快速 AC 总结

  1. 明确问题是连续子数组,直接优先使用滚动 DP 模板。
  2. 熟悉时间复杂度要求:若需要 O(m * n) 解决,选择滑动窗口或动态规划。
  3. 若需寻求更高效方法,尝试二分和哈希结合的解法。
  4. 练习经典变体问题如 LCS,使技术迁移更灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/71180.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 0132.分割回文串 II:动态规划

【LetMeFly】132.分割回文串 II&#xff1a;动态规划 力扣题目链接&#xff1a;https://leetcode.cn/problems/palindrome-partitioning-ii/ 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回符合要求的 最少分割次数 。 示例 …

iOS 实现UIButton自动化点击埋点

思路&#xff1a;我们HOOK UIControl的 addtarget:action:forControlEvents方法&#xff0c;交换UIControl的 addtarget:action:forControlEvents 方法的实现&#xff0c; 在交换的方法中添加原来响应的同时&#xff0c;再添加一个埋点响应&#xff0c;该响应方法实现了点击埋点…

C++蓝桥杯基础篇(六)

片头 嗨~小伙伴们&#xff0c;大家好&#xff01;今天我们来一起学习蓝桥杯基础篇&#xff08;六&#xff09;&#xff0c;练习相关的数组习题&#xff0c;准备好了吗&#xff1f;咱们开始咯&#xff01; 第1题 数组的左方区域 这道题&#xff0c;实质上是找规律&#xff0c;…

git -学习笔记

目录 基本操作语法 设置用户和邮箱 版本回退 工作区和暂存区 撤销修改 删除与恢复 一工作区删除了&#xff0c;但是暂存区没删除 二工作区误删了&#xff0c;暂存区还有 github-Git 连接 报错解决-push远程仓库被拒绝 远程库 分支 分支冲突 储藏分支 回到当前分…

Windows本地Docker+Open-WebUI部署DeepSeek

最近想在自己的电脑本地部署一下DeepSeek试试&#xff0c;由于不希望污染电脑的Windows环境&#xff0c;所以在wsl中安装了ollama&#xff0c;使用ollama拉取DeepSeek模型。然后在Windows中安装了Docker Desktop&#xff0c;在Docker中部署了Open-WebUI&#xff0c;最后再在Ope…

力扣785. 判断二分图

力扣785. 判断二分图 题目 题目解析及思路 题目要求将所有节点分成两部分&#xff0c;每条边的两个端点都必须在不同集合中 二分图&#xff1a;BFS/DFS/并查集 因为图不一定联通&#xff0c;所以枚举所有点都做bfs(如果没联通的话) 代码 class Solution { public:bool is…

springboot之集成Elasticsearch

目录 二、Elasticsearch 是什么&#xff1f;三、Elasticsearch 安装四、Springboot 集成 Elasticsearch 的方式五、创建项目集成 Elasticsearch 2.创建 Spring Initializr 项目 es &#xff08;3&#xff09;.新建实体类 User&#xff08;4&#xff09;.新建 dao 接口类 UserR…

[Lc滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数

目录 1. 长度最小的字数组 题解 代码 ⭕2.无重复字符的最长子串 题解 代码 3.最大连续1的个数 III 题解 代码 4.将 x 减到 0 的最小操作数 题解 代码 1. 长度最小的字数组 题目链接&#xff1a;209.长度最小的字数组 题目分析: 给定一个含有 n 个 正整数 的数组…

数据集笔记:新加坡 地铁(MRT)和轻轨(LRT)票价

数据连接 data.gov.sg 2024 年 12 月 28 日起生效的新加坡地铁票价 该数据集包含 MRT 和 LRT 票价的信息&#xff0c;包括&#xff1a; 票价类型&#xff08;Fare Type&#xff09;&#xff1a;成人票、学生票、老年人票、残障人士票等。适用时间&#xff08;Applicable Tim…

湘潭大学计算机复试详细攻略(调剂)

一&#xff0c;写在前面的话 ① 首先&#xff0c;能完成考试初试来到这里的都是勇士。不管结果如何&#xff0c;不管成绩如何。我都在这里真心的祝福你以后一帆风顺。 ② 目前学历贬值严重&#xff0c;如果是成绩不理想的话&#xff0c;我建议能工作就去工作&#xff0c;工作不…

【前端基础】Day 3 CSS-2

目录 1. Emmet语法 1.1 快速生成HTML结构语法 1.2 快速生成CSS样式语法 2. CSS的复合选择器 2.1 后代选择器 2.2 子选择器 2.3 并集选择器 2.4 伪类选择器 2.4.1 链接伪类选择器 2.4.2 focus伪类选择器 2.5 复合选择器总结 3. CSS的元素显示模式 3.1 什么是元素显示…

不同数据类型在数据库和编程语言之间的对应关系表

不同数据类型在数据库和编程语言之间的对应关系表 MySql 与 C# MySqlC#varcharstringbigintlongbigint unsignedulongintintint unsigneduintsmallintshortsmallint unsignedushortVARCHAR(36)GuidsmalldatetimeDateTimedateDateTimedatetimeDateTimetimestampDateTimefloatf…

RabbitMQ操作实战

1.RabbitMQ安装 RabbitMQ Windows 安装、配置、使用 - 小白教程-腾讯云开发者社区-腾讯云下载erlang&#xff1a;http://www.erlang.org/downloads/https://cloud.tencent.com/developer/article/2192340 Windows 10安装RabbitMQ及延时消息插件rabbitmq_delayed_message_exch…

DeepSeek教unity------UI元素长按响应

主要功能说明&#xff1a; ​长按检测&#xff1a;通过记录指针按下的时间&#xff0c;判断是否达到 longClickTime&#xff0c;从而触发长按事件。​状态管理&#xff1a;使用 StateEnum 枚举管理点击项的当前状态&#xff08;未按下、按下等待长按、长按已触发&#xff09;。…

【北京迅为】itop-3568 开发板openharmony鸿蒙烧写及测试-第2章OpenHarmony v3.2-Beta4版本测试

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

stm32hal库寻迹+蓝牙智能车(STM32F103C8T6)

简介: 这个小车的芯片是STM32F103C8T6&#xff0c;其他的芯片也可以照猫画虎,基本配置差不多,要注意的就是,管脚复用,管脚的特殊功能,(这点不用担心,hal库每个管脚的功能都会给你罗列,很方便的.)由于我做的比较简单,只是用到了几个简单外设.主要是由带霍尔编码器电机的车模,电机…

SQL命令详解之操作数据库

操作数据库 SQL是用于管理和操作关系型数据库的标准语言。数据库操作是SQL的核心功能之一&#xff0c;主要用于创建、修改和删除数据库对象&#xff0c;如数据库、表、视图和索引等。以下是SQL中常见的数据库操作命令及其功能简介&#xff1a; 1. 查询数据库 查询所有的数据库…

Go红队开发—编解码工具

文章目录 开启一个项目编解码工具开发Dongle包Base64编解码摩斯密码URL加解密AES加解密 MD5碰撞工具开发 开启一个项目 这作为补充内容&#xff0c;可忽略直接看下面的编解码&#xff1a; 一开始用就按照下面的步骤即可 1.创建一个文件夹&#xff0c;你自己定义名字(建议只用…

Starrocks入门(二)

1、背景&#xff1a;考虑到Starrocks入门这篇文章&#xff0c;安装的是3.0.1版本的SR&#xff0c;参考&#xff1a;Starrocks入门-CSDN博客 但是官网的文档&#xff0c;没有对应3.0.x版本的资料&#xff0c;却有3.2或者3.3或者3.4或者3.1或者2.5版本的资料&#xff0c;不要用较…

工程化与框架系列(10)--微前端架构

微前端架构 &#x1f3d7;️ 微前端是一种将前端应用分解成更小、更易管理的独立部分的架构模式。本文将详细介绍微前端的核心概念、实现方案和最佳实践。 微前端概述 &#x1f31f; &#x1f4a1; 小知识&#xff1a;微前端的核心理念是将前端应用分解成一系列独立部署、松耦…