LeetCode 718 - 最长重复子数组
LeetCode 718 - 最长重复子数组 是一个典型的数组和字符串问题,适合考察动态规划、滑动窗口和二分查找等多种编程能力。掌握其多种解法及变体能够有效提高处理字符串和数组算法的能力。
题目描述
- 输入: 两个整数数组
nums1和nums2。 - 输出: 两个数组中存在的最长的连续重复子数组的长度。
- 要求: 时间复杂度尽可能优化。
示例
输入: 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),其中
m和n是数组长度。 - 空间复杂度: 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进行比较。 - 在滑动的过程中寻找最大公共子数组长度。
- 如果
nums1和nums2不完全对齐,就逐步滑动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:二分查找 + 哈希
核心思想
- 使用滑动窗口与哈希表结合,通过 二分查找 在所有可能的子数组长度中快速找到最长重复子数组长度。
- 利用暴力检查或 Rabin-Karp 哈希验证是否存在长度为
mid的公共子数组:- 用窗口提取长度为
mid的子数组,进行比对。
- 用窗口提取长度为
- 使用二分查找:
- 如果某个长度是可行的(存在共同子数组),增加长度;
- 如果不可行,减小长度。
- 利用暴力检查或 Rabin-Karp 哈希验证是否存在长度为
模板代码
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)),为哈希表的空间。
变体问题
-
最长公共子序列 (LCS):
- 两数组中非连续元素符合顺序的最长子序列长度。
- DP 思路与本题类似,但不要求元素连续。
-
最长公共前缀 (Longest Common Prefix):
- 但不局限于以何种顺序,重点是找最大前缀。
-
编辑距离问题:
- 在两个字符串之间,进行最少字符操作(包括插入、删除、替换)使其相等。
-
字符串匹配问题(KMP 或 Rabin Karp):
- 查找两个字符串的最大匹配区段。
快速 AC 总结
- 明确问题是连续子数组,直接优先使用滚动 DP 模板。
- 熟悉时间复杂度要求:若需要 O(m * n) 解决,选择滑动窗口或动态规划。
- 若需寻求更高效方法,尝试二分和哈希结合的解法。
- 练习经典变体问题如 LCS,使技术迁移更灵活。
相关文章:
LeetCode 718 - 最长重复子数组
LeetCode 718 - 最长重复子数组 是一个典型的数组和字符串问题,适合考察动态规划、滑动窗口和二分查找等多种编程能力。掌握其多种解法及变体能够有效提高处理字符串和数组算法的能力。 题目描述 输入: 两个整数数组 nums1 和 nums2。输出: 两个数组中存在的最长的…...
什么是预训练语言模型下游任务?
问题:Word2Vec模型是预训练模型吗? 由于训练的特性,word2Vec模型一定是与训练模型。给定一个词先使用独热编码然后使用预训练好的Q矩阵得到这个词的词向量。这里指的是词向量本身就是预训练的语言模型。 什么是下游任务? 在自然…...
jvm内存模型,类加载机制,GC算法,垃圾回收器,jvm线上调优等常见的面试题及答案
JVM内存模型 JVM内存模型包括哪些区域 答案:JVM内存模型主要包括以下区域: 程序计数器:是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器,用于记录正在执行的虚拟机字节码指令的地址。Java虚拟机…...
[Windows] 免费电脑控制手机软件 极限投屏_正式版_3.0.1 (QtScrcpy作者开发)
[Windows] 极限投屏_正式版 链接:https://pan.xunlei.com/s/VOKJf8Z1u5z-cHcTsRpSd89tA1?pwdu5ub# 新增功能(Future): 支持安卓14(Supports Android 14)提高投屏成功率(Improve the success rate of mirror)加快投屏速度(Accelerate screen mirrorin…...
C++初阶—list类
第一章:list的介绍及使用 1.1 list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指…...
【子网掩码计算器:Python + Tkinter 实现】
子网掩码计算器:Python Tkinter 实现 引言代码功能概述代码实现思路1. 界面设计2. 功能实现3. 事件处理 子网掩码计算器实现步骤1. 导入必要的库2. 定义主窗口类 SubnetCalculatorApp3. 创建菜单栏4. 创建界面组件5. 判断 IP 地址类别6. 计算子网信息7. 其他功能函…...
入门基础项目(SpringBoot+Vue)
文章目录 1. css布局相关2. JS3. Vue 脚手架搭建4. ElementUI4.1 引入ElementUI4.2 首页4.2.1 整体框架4.2.2 Aside-logo4.2.3 Aside-菜单4.2.4 Header-左侧4.2.5 Header-右侧4.2.6 iconfont 自定义图标4.2.7 完整代码 4.3 封装前后端交互工具 axios4.3.1 安装 axios4.3.2 /src…...
Nginx+PHP+MYSQL-Ubuntu在线安装
在 Ubuntu 上配置 Nginx、PHP 和 MySQL 的步骤如下: 1. 更新系统包 首先,确保系统包是最新的: sudo apt update sudo apt upgrade2. 安装 Nginx 安装 Nginx: sudo apt install nginx启动并启用 Nginx 服务: sudo…...
车载以太网-基于linux的ICMP协议
对于车载以太网-ICMP的技术要求: /** ICMP报文格式解析* -----------------* ICMP协议用于网络诊断和错误报告,常见应用包括Ping测试。* ICMP报文结构包括:IP头部、ICMP头部和ICMP数据部分。* 下面详细介绍每个部分的结构、字段的作用以及如何解析它们。* * ICMP头部结构:*…...
虚拟机快照与linux的目录结构
虚拟机快照是对虚拟机某一时刻状态的完整捕获,包括内存、磁盘、配置及虚拟硬件状态等,保存为独立文件。 其作用主要有数据备份恢复、方便系统测试实验、用于灾难恢复以及数据对比分析。具有快速创建和恢复、占用空间小、可多个快照并存的特点。在管理维…...
Unity小功能实现:鼠标点击移动物体
1、功能描述 当玩家点击鼠标时,场景中的物体会移动到鼠标点击的位置。这个功能可以用于控制角色移动、放置物体等场景。 2、实现步骤 创建Unity项目:首先,打开Unity并创建一个新的3D项目。 添加3D物体:在场景中创建一个3D物体&am…...
算法题笔记(自用)——Python
目录 一. 进制&位运算&ASCAII 二. format格式化输出 1. 基本用法 2. 位置参数 3. 格式化数字 4. 对齐和填充 5. 格式化二进制、八进制、十六进制 6. 格式化百分比 7. 格式化科学计数法 8. 格式化字符串字面量(f-string) 三. 字符串 使…...
爬虫系列之【数据解析之JSON】《三》
目录 前置知识 一、 json.loads():JSON 转 Python 数据 二、json.dump():python数据 转 json 并写入文件 三、json.loads() :json 转 python数据 四、json.load() :json 转 python数据(在文件操作中更方便…...
了解Java集合的概念和体系:Collection<T>、Collections与Stream的使用
学习目标 本文知识是对集合层级的介绍,应用开发中实际使用的是他们的子级,感兴趣的小伙伴或者想深入了解有关Java集合知识的朋友可以选择阅读! Stream的方法使用使用部分代码块内大多有两种实现方式,是为了更好的理解方法底层的代…...
进程优先级和进程切换 ─── linux第12课
目录 Z(zombie)-僵尸进程 僵尸进程危害 孤儿进程 编辑 进程优先级 查看系统进程 用top命令更改已存在进程的nice: 其他概念 进程切换 进程如何切换 进程的调度 进程 内核数据结构 代码和数据 创建进程时 ,先创建内核数据结构 再加载代码和数据 进程退…...
光速解决phpstudy无法启动MySQL服务
问题描述 在初步安装使用phpstudy时,会出现mysql服务启动失败的情况,具体表现为点击一键启动后,mysql启动又立即停止 原因及解决方法: phpstudy数据库无法启动有以下几个原因,可以看看自己是第几种: 服务名…...
深度学习五大模型:CNN、Transformer、BERT、RNN、GAN详细解析
# 深度学习五虎将:当CNN遇见Transformer的奇幻漂流 ## 序章:AI江湖的兵器谱排行 2012年,多伦多大学的厨房里,Hinton的学生们用GPU煎了个"AlexNet"荷包蛋,从此开启了深度学习的热兵器时代。如今五大模型各显…...
txt 转 json 使用python语言
需求: 把如下的txt文档转成json输出 代码 import jsondef txt_to_json(input_file, output_file):data_list []with open(input_file, r, encodingutf-8) as f:for line in f:# 分割数据并去除换行符parts line.strip().split(,)print(f"{parts}")print(type(par…...
FPGA开发,使用Deepseek V3还是R1(4):Deepseek参数配置
以下都是Deepseek生成的答案 FPGA开发,使用Deepseek V3还是R1(1):应用场景 FPGA开发,使用Deepseek V3还是R1(2):V3和R1的区别 FPGA开发,使用Deepseek V3还是R1&…...
Cargo, the Rust package manager, is not installed or is not on PATH.
今天在Windows操作系统上通过pip 安装jupyter的时候遇到这个报错,Cargo, the Rust package manager, is not installed or is not on PATH.。 解决办法 官网:https://rustup.rs/# 下载:https://win.rustup.rs/x86_64 安装完成之后,…...
Go开发框架Sponge+AI助手协同配合重塑企业级开发范式
在互联网高速发展的今天,企业级应用系统面临着日益复杂的业务逻辑和不断增长的开发需求。如何在保证高质量、高效率的前提下快速交付项目,成为了开发者亟需解决的问题。本文将详细介绍如何利用开源的 go 开发框架 Sponge 与 AI 助手协同配合全过程&#…...
从递归到动态规划(三维)
问题描述 假设有一个三维空间的网格,其大小为 m x n x p。我们从坐标 (0, 0, 0) 出发,要到达坐标 (m - 1, n - 1, p - 1)。每次只能在三个方向上移动:向前(x 坐标加 1)、向右(y 坐标加 1)或向上…...
JavaWeb个人笔记
技术栈 前端 : HTML CSS JavaScript ES6 Nodejs npm vite vue3 router pinia axios element-plus 后端:HTTP xml Tomcat Servlet Request Response Cookie Sesssion Filter Listener MySQL JDBC Druid Jackson lombok jwt . HTML <!DOCTYPE html> 文档声…...
【vue-echarts】——01.认识echarts
文章目录 前言一、echarts二、使用步骤1.vue cli创建项目并安装第三方模块echarts2.显示图表总结前言 定制的数据可视化图表。ECharts最初由百度团队开源,并于2018年初捐赠给Apache基金会,成为ASF孵化级项目。2021年1月26日晚,Apache基金会官方宣布ECharts项目正式毕业。 一…...
http报文的content-type参数和spring mvc传参问题
很早之前博主聊过HTTP的报文结构以及其中和传参相关的重要参数content-type还有spring mvc,以前的三篇文章: HTTP与HTTPS协议详解:基础与安全机制-CSDN博客 详解Http的Content-Type_content-type application-CSDN博客 如何在Spring Boot中…...
005 公网访问 docker rocketmq
文章目录 创建自定义网络创建NameServer容器创建Broker容器正式开始启动 Nameserver 容器启动 Broker 容器并关联 Nameserverdocker exec -it rmqbroker vi /etc/rocketmq/broker.conf检查 namesrv 解析检查 Broker 注册状态Nameserver 日志Broker 日志检查容器日志手动指定 Br…...
14. LangChain项目实战1——基于公司制度RAG回答机器人
教学视频: 12. 基于Gradio搭建基于公司制度RAG_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV11VXRYTErZ/ 环境配置: python版本:3.10.8 服务器:Ubuntu 依赖包requirements.txt文件内容: aiofiles23.2.1 …...
FPGA开发,使用Deepseek V3还是R1(6):以滤波器为例
以下都是Deepseek生成的答案 FPGA开发,使用Deepseek V3还是R1(1):应用场景 FPGA开发,使用Deepseek V3还是R1(2):V3和R1的区别 FPGA开发,使用Deepseek V3还是R1&#x…...
JVM常用概念之垃圾回收设计与停顿
在我们应用程序运行期间,我们是需要尽可能避免垃圾回收。 图1:不同垃圾回收器的设计(黄色代表STW,绿色代表并发) 实验 计算机配置 Hardware Overview:Model Name: MacBook ProModel Identifier: MacBookPro14,2Pro…...
uniapp-原生android插件开发摘要
uni-app在App侧的原生扩展插件,支持使用java、object-c等原生语言编写,从HBuilderX 3.6起,新增支持了使用uts来开发原生插件。 基础项目 UniPlugin-Hello-AS工程请在App离线SDK中查找 基础项目(App离线SDK)已经配置好了自定义插件所需要的…...
