动态规划经典算法之最长公共子序列问题

开篇

最长公共子序列问题又称为LCS问题,这个问题和动态规划的很多问题无论从思路还是框架上都非常相似,比如编辑距离问题(后续的文章中会讲到),所以掌握这个最经典的LCS问题是很有必要的。话不多说我们开始吧。

题目描述

题目就是让我们求两个字符串的最长公共序列,字符的相对顺序不能变,求出最长序列长度。

输入:str1 = "abdefc",str2 = "aecf"
输出:长度为3
解释:最长公共子序列为"aec",它的长度为3

这个问题为什么可以通过动态规划来解决呢?因为我们的最长公共子序列一定属于一个字符串,所以其必是任何一个字符串的子序列。那么问题就变成了求子问题,求子问题最主要的步骤就是穷举+剪枝,所以我们可以使用动态规划来穷举做选择,然后通过剪枝来控制状态 更新。

题目分析

首先我们先定义dp table用来存储穷举的每一个状态对应的最长公共子序列长度。
在这里插入图片描述

我们定义dp[i][j]为s1[1…i]和s2[1…j]的最长公共子序列长度。
确定base case
根据这个定义我们可以确定我们的base case。即:

dp[....][0] = 0
dp[0][....] = 0
解释:当一个字符串为空的,两个字符串的最长公共子序列一定为0

确定状态转移方程
状态转移方程的确定通常是动态规划中最难的部分也是最重要的部分,找对了状态转移方程如果问题都解不对的话,那也只是一些小错误,总的框架还是没问题的。
我们先来看一下下图:
在这里插入图片描述
我们可以看到,如果str1[i] == str2[j],则我们的最长公共子序列长度应该+1,从哪个状态+1呢?答案肯定是从上一状态,即i的前一位置和j的前一位置。

dp[i][j]=dp[i-1][j-1] + 1

那么如果两个字符不相等,即str1[i] != str2[j],则我们应该至少保留一个然后求丢弃一个。
则我们的状态转移方程如下:

dp[i][j] = max(dp[i][j-1],dp[i-1][j])

综合以上两点我们可以直接翻译出代码:

def LCS(self,str1,str2):
	m = len(str1)
	n = len(str2)
	# 这里相当于设置好了base case
	dp = [[0 for _ in range(n + 1] for _ in range(m + 1)]
	if not str1 or not str2:
		return 0
	for i in range(1,m + 1):
		for j in range(1,n + 1):
			if str1[i - 1] == str2[j - 1]:
				dp[i][j] = dp[i-1][j-1] + 1
			else:
				dp[i][j] = max(dp[i-1][j],dp[i][j-1])
	return dp[-1][-1]

这里需要说明一定,为什么我们比较的是str1[i -1]和str2[j-1]呢?
因为我们的base case是针对dp[…][0]和dp[0][…]的,所以当i=j=1时,我们才是刚开始计算最长公共子序列,所以此时我们应该比较str1[0]和str2[0],然后用dp[0][0]去更新dp[1][1]。所以当我们设置好了base case,我们就应该跳过索引0,从1开始。但是索引0是有字符的没所以在索引0我们也应该进行比较。

答疑

这次博客发出来之前先给我的朋友看了一下,他问了我一个问题我觉得确实有必要拿出来说一下。那就是当str1[i] != str2[j]的时候,我们保留了一个,丢弃了一个,那如果最终这个这两个字符都不在我们的最长公共子序列中呢?
在这里插入图片描述
如果两个字符都不在我们的最长公共子序列中,那么我们就将二者全部淘汰,无一保留,那么状态转移方程应该写为:

dp[i][j] = max(dp[i][j-1],
		dp[i-1][j],
		dp[i-1][j-1])

但是我们求的是最大值,而显然dp[i-1][j-1]小于等于dp[i][j-1]或者dp[i-1][j],所以我们不是没有考虑这两个字符都不出现在最长公共子序列中的情况,而是省略掉了,因为这种情况下的公共子序列长度一定不是最大的,或者不是唯一最大的,因此化简成:

dp[i][j] = max(dp[i][j-1],dp[i-1][j])

总结

如本文所述,我们还是强调所有动态规划问题的基本框架:
穷举状态,做选择,列出状态转移方程
这个问题和以后的很多问题非常相似,是类似题目的启蒙问题,比如我们的编辑距离问题,和它的状态转移方程就十分类似,后续我们会谈到。
最后列出一个dp table中的状态转移图例方便大家更好理解:
在这里插入图片描述

原创文章 101 获赞 13 访问量 2315

猜你喜欢

转载自blog.csdn.net/weixin_44755413/article/details/105880385