一、题:给定两个字符串text1和text2,返回这两个字符串的最长公共子序列的长度。如果不存在公共子序列,返回0。
一个字符串的子序列是指这样一个新的字符串:它是由原字符串在不改变字符串的相对顺序的情况下删除某些字符后组成的新的字符串。
二、思路
1.dp数组的含义
dp[i][j]表示:长度为[0-(i-1)]的字符串text1与长度为[0-(j-1)]的字符串text2的最长公共子序列数为dp[i][j]
定义为i-1和j-1可以看二维数组定义后的图,帮助理解
text1/text2 | a | c | e | |
** | ** | ** | ** | |
a | ** | dp[1][1] | ** | ** |
b | ** | ** | ** | ** |
c | ** | ** | ** | ** |
d | ** | ** | dp[4][2] | ** |
e | ** | ** | ** | ** |
例如表中的dp[1][1]表示text1[1-1]=text1[0](‘a’)之前的字符串与text2[1-1]=text2[0](‘a’)之前的字符串的最大公共子序列。
表中的dp[4][2]表示text1[4-1]=text2[3](‘d’)之前的字符串与text2[2-1]=text1[1](‘c’)之前的字符串的最大公共子序列
可以看出每个二维数组的值dp[i][j]正上方和正左方对应的字符串值在数组里就是text1[i-1]和text2[j-1]
2、递推公式
最大公共子序列问题也分为两种情况:1.text1[i-1]与text2[j-1]相同 2.text1[i-1]与text2[j-1]不相同
相同:如果text1[i-1]与text2[j-1]相同,此时又多了一个公共子序列元素,所以dp[i][j]=dp[i-1][j-1]+1
不相同:如果text1[i-1]与text2[j-1]不相同,那么就要看dp[i-1][j]与dp[i][j-1]中最大的公共子序列,即text1[i-2]与text2[j-1]的最长公共子序列和text1[i-1]与text2[j-2]的最长公共子序列的最大值
即dp[i][j]=max(dp[i-1][j],dp[i][j-1])
3、dp数组初始化
从递推公式可以看出dp[i][j]是由三个方向递推而来的即dp[i-1][j-1](dp[i][j]的左右上角)、dp[i-1][j](dp[i][j]的正上方)、dp[i][j-1](dp[i][j]的正左方)
因此应该初始化的二维数组为dp[i][0]和dp[0][j]。
dp[i][0]表示text1[0--(i-1)]和空字符串的最长公共子序列,那么自然是0,所以dp[i][0]=0,同理dp[0][j]=0
其余的二维数组值会随着递推公式计算补充,会被覆盖掉,所以复制多少都可以,这里全部赋值为0了
4、遍历顺序
从递推公式的递推dp[i][j]的三个方向可以看出,是从前向后,从左到右的
5、举例推导dp数组
dp[1][1]=1,因为text1[0]与text2[0]相等,所以最大公共子序列值为0+1=1
dp[1][2]=1,因为text1[0]与text2[1]不相等,dp[0][2]=0,dp[1][1]=1,最大值为1,所以最长公共子序列为1
。。。。
dp[4][2]=2,因为text1[3]与text2[1]不相同,dp[3][2]=2,dp[4][1]=1,最大值为2,所以最长公共子序列为2
。。。。
三、代码(Python3)