【DP】2023Q1A-寻找重复代码
题目描述与示例
题目
小明负责维护项目下的代码,需要查找出重复代码,用以支撑后续的代码优化,请你帮助小明找出重复的代码。 重复代码查找方法:以字符串形式给出两行代码text1
,text2
(字符串长度1 < len(text1),len(text2) <= 100
,由英文字母、数字和空格组成),找出两行代码中的最长公共子串。如果不存在公共子串,返回空字符串。
注意子串是连续的。
输入
输入的参数text1
,text2
分别表示两行代码
输出
输出任一最长公共子串。
示例一
输入
hello123world
hello123abc4
输出
hello123
示例二
输入
private_void_method
public_void_method
输出
_void_method
示例三
输入
hiworld
hiweb
输出
hiw
解题思路
注意:本题和LC718. 最长重复子数组几乎完全一致。唯一区别在于,本题要计算的不是最长公共子串的长度,而是要输出最长公共子串本身。
这是一个典型的dp问题。我们考虑动态规划三部曲:
dp
数组的含义是什么?
dp
数组是一个大小为(N+1)*(M+1)
的二维矩阵,dp[i][j]
表示text1
前i
个元素和text2
前j
个元素的公共的、长度最长的连续子串的长度。
- 动态转移方程是什么?
- 如果发现
text1
的当前元素,即位置为i-1
的元素,与text2
的当前元素即位置为j-1
的元素**相同。**此时,找到了一个公共元素,公共的、长度最长的子串的长度加1
。
if text1[i-1] == text2[j-1]:
dp[i][j] = dp[i - 1][j - 1] + 1
dp
数组如何初始化?
dp[0][0]
表示text1
前0
个元素和text2
前0
个元素的公共的、长度最长的子串的长度,此时公共的、长度最长的子串的长度为0
。text1
或者text2
没有字符时,公共的、长度最长的子串的长度都为0
。
dp = [[0] * (n + 1) for _ in range(m + 1)]
dp[0][0] = 0
for i in range(1, m+1):
dp[i][0] = 0
for j in range(1, n+1):
dp[0][j] = 0
考虑完上述问题后,代码其实呼之欲出了。
代码
# 题目:2023Q1A-寻找重复代码
# 分值:100
# 作者:闭着眼睛学数理化
# 算法:动态规划(LCS问题)
# 代码看不懂的地方,请直接在群上提问
text1 = input()
text2 = input()
# 获取 text1 的长度
m = len(text1)
# 获取 text2 的长度
n = len(text2)
# 设置数组 dp,用来存储 text1 和 text2 公共的、长度最长的子串的长度
# dp[0][0] 表示 text1 前 0 个元素和 text2 前 0 个元素的公共的、长度最长的子串的长度
# dp[2][3] 表示 text1 前 2 个元素和 text2 前 3 个元素的公共的、长度最长的子串的长度
# dp[i][j] 表示 text1 前 i 个元素和 text2 前 j 个元素的公共的、长度最长的子串的长度
# 前 i 个元素的区间为 [0, i-1]
# dp[m][n] 表示 text1 前 m 个元素和 text2 前 n 个元素的公共的、长度最长的子串的长度
# 前 m 个元素的表示区间为 [0, m],前 n 个元素的表示区间为 [0, n]
# 因此,dp 数组的长度为 m + 1 和 n + 1
dp = [[0] * (n + 1) for _ in range(m + 1)]
# maxLength 表示 dp 数组中的最大值
maxLength = 0
# 初始化答案变量为空串
ans = ""
# 1. 初始化dp数组
# dp[0][0] 表示 text1 前 0 个元素和 text2 前 0 个元素的公共的、长度最长的子串的长度
# text1 text2 也没有元素
# 因此,公共的、长度最长的子串的长度为 0
dp[0][0] = 0
# text1 没有元素 或者 text2 没有字符时,公共的、长度最长的子串的长度都为 0
for i in range(1, m+1):
dp[i][0] = 0
for j in range(1, n+1):
dp[0][j] = 0
# i 从 1 开始,直到 m 位置,遍历 text1 的前 i 个元素
for i in range(1, m+1):
# j 从 1 开始,直到 n 位置,遍历 text2 的前 j 个元素
for j in range(1, n+1):
# 2. 动态转移方程
# 如果发现 text1 的当前元素,即位置为 i - 1 的元素
# 与 text2 的当前元素,即位置为 j - 1 的元素【相同】
# 此时,找到了一个公共元素,公共的、长度最长的子串的长度加 1
if text1[i - 1] == text2[j - 1]:
# dp[i][j] 表示 text1 前 i 个元素和 text2 前 j 个元素的公共的、长度最长的子串的长度
# dp[i - 1][j - 1] 表示 text1 前 i - 1 个元素和 text2 前 j - 1 个元素的公共的、长度最长的子串的长度
dp[i][j] = dp[i - 1][j - 1] + 1
# 更新最长的子串的长度
if maxLength < dp[i][j]:
maxLength = dp[i][j]
# 最长子串长度为maxLength,对于text1而言,
# 当前结束位置为i,当前开始位置为i-maxLength
# 这里换成text2[j-maxLength: j]也是一样的
ans = text1[i-maxLength: i]
# 返回结果
print(ans)
时空复杂度
时间复杂度:O(MN)
。dp过程需要经历双重循环。
空间复杂度:O(MN)
。二维dp数组所占据的空间。
M
、N
分别为text1
、text2
的长度。
华为OD算法冲刺训练
-
华为OD算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
-
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
-
30+天陪伴式学习,20+直播课时,300+动画图解视频,200+LeetCode经典题,100+华为OD真题,还有简历修改与模拟面试将为你解锁
-
可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)
-
绿色聊天软件戳
sheepvipvip
了解更多