尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

0x3f第14天 最长公共子序列

0x3f第14天 最长公共子序列
📅 发布时间:2026/6/18 6:05:48

1.子数组/子串是连续的 子序列不一定是连续的 abcde中ace就是子序列

2.给定两个字符串,求两个的最长公共子序列,dfs(i,j)定义:序列1的前i个字母和序列2的前j个字母 的最长公共子序列

下一个问题:序列1前i-1个字母和序列二前j-1个字母

序列1前i个字母和序列二前j-1个字母

序列1前i-1个字母和序列二前j个字母

可以简化:

dfs(i,j) = dfs(i-1,j-1)+1 s[i]=t[j]

dfs(i,j) = max(dfs(i-1,j),dfs(i,j-1)) s[i]≠t[j]

最长公共子序列

1.回溯法

时间复杂度 nm 空间复杂度 nm

class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: n = len(text1) m = len(text2) @cache def dfs(i,j): if i<0 or j<0: return 0 if text1[i]==text2[j]: return dfs(i-1,j-1)+1 else: return max(dfs(i-1,j),dfs(i,j-1)) return dfs(n-1,m-1)

2.递推

先得到递推公式

f[i][j] = f[i-1][j-1]+1 s[i]=t[j]

max(f[i-1][j],f[i][j-1] s[i]≠t[j]

f = [[0]*(m+1)for _ in range(n+1)] for i,x in enumerate(text1): for j,y in enumerate(text2): if x==y: f[i+1][j+1] = f[i][j]+1 else: f[i+1][j+1] = max(f[i][j+1],f[i+1][j]) return f[n][m]

3.空间优化

可以发现更新f[i+1][j+1]需要三个值,左边,上面,左上,但左上的数据会被覆盖,引入pre变量

pre = f[0]不能写在循环外面,核心原因是:进入 j 循环后,pre会逐步保存「上一个 j 位置的旧值」,精准匹配二维 DP 中dp[i-1][j-1]的语义。

空间复杂度 m

f = [0]*(m+1) for i,x in enumerate(text1): pre = f[0] for j,y in enumerate(text2): tmp = f[j+1] if x==y: f[j+1] = pre+1 else: f[j+1] = max(f[j+1],f[j]) pre = tmp return f[m]

编辑距离

为什么叫编辑距离:

“编辑”:指对字符串的修改操作(插入、删除、替换是文本编辑中最基础的三种操作)

距离: 操作次数越少,差异越小,距离越近

dfs(i, j)的定义表示将s[0..i](s 的前 i+1 个字符)转换为t[0..j](t 的前 j+1 个字符)所需的最少操作数。

dfs(i-1, j) + 1→ 对应「删除操作」

含义:先将s[0..i-1]转换为t[0..j](操作数是dfs(i-1, j)),再删除s[i](+1 次操作)

dfs(i, j-1) + 1→ 对应「插入操作」

  • 含义:先将s[0..i]转换为t[0..j-1](操作数是dfs(i, j-1)),再插入t[j]到 s 中(+1 次操作)。

dfs(i-1, j-1) + 1→ 对应「替换操作」

含义:先将s[0..i-1]转换为t[0..j-1](操作数是dfs(i-1, j-1)),再将s[i]替换为t[j](+1 次操作)

而如果s[i] == t[j],则不需要任何操作,直接继承dfs(i-1, j-1)的结果(这是 “无操作” 的情况)。

1.回溯法

1.回溯公式:

dfs(i,j) = dfs(i-1,j-1) if s[i] == t[j]

dfs(i,j) = min(dfs(i,j-1),dfs(i-1,j),dfs(i-1,j-1)) +1 if s[i] ≠ t[j]

插入 删除 替换

2.边界条件:if i<0:return j+1 把j全加一遍,就相同了

if j<0:return i+1 把i全删了,就相同了

class Solution: def minDistance(self, word1: str, word2: str) -> int: n = len(word1) m = len(word2) @cache def dfs(i,j): if i<0:return j+1 if j<0:return i+1 if word1[i]==word2[j]: return dfs(i-1,j-1) else: return min(dfs(i,j-1),dfs(i-1,j),dfs(i-1,j-1))+1 return dfs(n-1,m-1)

2.递推:

我卡住的地方:

if i<0:return j+1
if j<0:return i+1 怎么转换到二维数组里

首先 dfs 的定义是将 text1 前 i 转换为 text2 前 j 最少需要的操作次数

DP 的f[0][j]:对应递归的i=-1,此时 DP 的j对应递归的j-1→ 应返回(j-1)+1 = j(而非j+1)

综上:i<0 对应的是 f[0][j] 数组的第一行 j+1 在这是 j

j<0对应的是 f[i][0]数组的第一列 i+1在这是i

所以边界条件:

for j in range(m+1):

f[0][j] = j

for i in range(n+1):

f[i][0] = i

f = [[0]*(m+1)for _ in range(n+1)] for j in range(m+1): f[0][j] = j for i in range(n+1): f[i][0] = i for i,x in enumerate(word1): for j,y in enumerate(word2): if x==y: f[i+1][j+1] = f[i][j] else: f[i+1][j+1] = min(f[i+1][j],f[i][j+1],f[i][j])+1 return f[n][m]

3.空间优化

和最长公子序列不同的是,这个题的二维数组的第一行和第一列是动态的,而最长公子序列的第一行和第一列都是0,所以这个题要考虑的更多

1.一维数组的创建:

f = [j for j in range(m+1)] 并不是简单的创了一个全是0 的数组

2.pre = f[0] f[0] = i+1 pre记录旧值,f[0] = i+1对应的是

dfs的 for i in range(n+1):
f[i][0] = i的操作

综合起来达到动态的f[0]的效果

f = [j for j in range(m+1)] for i,x in enumerate(word1): pre = f[0] f[0] = i+1 for j,y in enumerate(word2): temp = f[j+1] if x==y: f[j+1] = pre else: f[j+1] = min(f[j],f[j+1],pre) +1 pre=temp return f[m]

最长递增子序列

1.回溯法:

若用常见的选或不选思路进行回溯,会递归遍历所有可能的子序列,比如数组长度为 n 时,子序列总数是 2ⁿ

修改思路,dfs(i)专注于 “以 i 结尾” 的子序列长度

外部遍历所有i,是为了覆盖 “以任意元素结尾” 的所有可能,从而得到全局最长长度。

此时dfs(i)的定义:以nums[i]结尾的最长递增子序列长度

外边再遍历一遍所有结尾情况,就能得出答案了

回溯公式:

dfs(i) = max {dfs(j)} +1 j<i and nums[j]<nums[i]

回溯代码:

def dfs(i):

temp = 0

for j in range(i):

if nums[j] < nums[i]:

temp = max(temp,dfs[j])

return temp+1

class Solution: def lengthOfLIS(self, nums: List[int]) -> int: n = len(nums) ans = 0 @cache def dfs(i): temp=0 for j in range(i): if nums[j]<nums[i]: temp = max(temp,dfs(j)) return temp+1 for i in range(n): ans = max(ans,dfs(i)) return ans

2.递推

递推公式:

f[i] = max{f(j)} +1 j<i and nums[j]<nums[i]

f = [0]*n for i in range(n): for j in range(i): if nums[j]<nums[i]: f[i] = max(f[i],f[j]) f[i] += 1 return max(f)

相关新闻

  • 代码源挑战赛 Round 43
  • fastboot驱动实现USB高速模式通信的技术要点
  • Unity游戏自动翻译终极指南:XUnity.AutoTranslator深度解析

最新新闻

  • 2026沈阳钻石回收行情多少?1克拉GIA钻戒变现真实估价科普 - 奢品小当家
  • MLOps生产实战:模型封装、服务化与监控三位一体指南
  • 2026 福州本土设计型装修公司哪家好?高口碑全案设计机构权威排名 - 资讯速览
  • TC652智能温控系统:从PWM风扇驱动到静音散热实战
  • 逆向AES加密接口与动态Token获取:Python爬虫实战解析
  • CoPaw:基于AI的Selenium自动化脚本智能生成实践

日新闻

  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号