惯例,先上美图:
什么是最长公共子序列?
1. 官方定义:最长公共子序列也称作最长公共子串(不要求连续,但要求次序),英文缩写为 LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。
2. 通俗的讲:就是给定两个字符串,求出这样一个最长的公共子序列的长度:子序列中的每个字符都能在两个原字符串中找到,并且每个字符的先后顺序和原串中的先后顺序一致。
例如:字符串S1为{a,s,d,f,g,h,q,e},S2为{b,s,f,h,q,w,p}。他们的最长公共子序列的长度就是4,即:sfhq。
为了统一,我们假定字符串本身并不算是其自身的子序列。比如:
S1 = “ASDF”
S2 = “AS”
它的最长子序列就是1 ,因为我们假定“AS”不算其自身的子序列。
如果它本身也算其自己的子序列,只需要在代码中做稍微的修改即可。
【解题思路】:
既然是使用动态规划来解决这个问题,我们就需要一个东西来保存当前的最优状态,这里,我们可以设MaxLen(i,j)表示字符串S1从下标为 0 到下标为 i-1 的字符形成的子串,与字符串S2从下标为 0 到下标为 j-1 的字符形成的子串的最长公共子序列的长度。即:MaxLen(i,j)为本题的“状态”。
假定 len_1 是字符串S1的长度,len_2 是字符串S2的长度,所以,最后求的东西就是MaxLen(len_1,len_2)。我们先分析题目写出递归方程,再根据递归方程总结出动态规划的方法。
- 递归出口:
{ M a x L e n ( n , 0 ) = 0 M a x L e n ( 0 , n ) = 0 \begin{cases} MaxLen(n,0)=0\\MaxLen(0,n)=0 \end{cases} { MaxLen(n,0)=0MaxLen(0,n)=0
上面公式中的n并不是特指字符串长度,它是一个小于字符串长度的一个任意数。
即:当两个字符串有任意一个只有一个字符时(下标从0 开始),他们的公共子序列就是0。因为我们假定自己不算自己的子序列。
- 递推公式:
M a x L e n ( i , j ) = { M a x L e n ( i − 1 , j − 1 ) + 1 , S1[i] == S2[j] m a x { M a x L e n ( i − 1 , j ) , M a x L e n ( i , j − 1 ) } S1[i] != S2[j] MaxLen(i,j) =\begin{cases}MaxLen(i-1,j-1)+1, & \text{S1[i] == S2[j]} \\max\{MaxLen(i-1,j),MaxLen(i,j-1)\}&\text{S1[i] != S2[j]}\end{cases} MaxLen(i,j)=