求最长公共子序列长度 (递归、动态规划)
所谓子序列,是指从序列中任意取出元素,按原序列中的顺序排序得到的序列。
所谓序列a和序列b的公共子序列,是指该子序列既是a的子序列,也是b的子序列。
递归思路:
设a的长度为n,b的长度为m,求解a[0,n-1]和b[0,m-1])的最长公共子序列LCS(a[0,n-1], b[0,m-1])无非三种情况
1) a或b为空序列,即m=0或n=0,a[0,n-1]和b[0,m-1])最长公共子序列即为空序列。LCS(a[0,n-1], b[0,m-1])
=
=
= “”
2) a、b非空,a和b序列最后一个元素相同,即a[n-1]==b[m-1], a[0,n-1]和b[0,m-1])的最长公共子序列,即为,a去掉末尾元素得到的序列,与b去掉末尾元素得到的序列,它们的最长公共子序列再加上a和b的末尾元素。比如说a[n-1]==b[m-1]==‘x’, 那么LCS(a[0,n-1], b[0,m-1])
=
=
= LCS(a[0,n-2], b[0,m-2]) + ‘X’
3) a、b非空,a和b最后一个元素不同,即a[n-1] != b[m-1], 那么a[0,n-1]和b[0,m-1])的最长公共子序列即为max(LCS(a[0,n-1], b[0,m]), LCS(a[0,n], b[0,m-1]) ) , 其含义为分别求①序列a去掉末尾元素的序列[0,n-2]与序列b[0,m-1]的最长公共子序列,②序列a[0,-1]与序列b去掉末尾元素的序列[0,m-2]的最长公共子序列。①和②中最长者,即为a[0,m-1]和b[0,m-1]的最长公共子序列。
递归:
#define max(a,b) (a)>(b)?(a):(b)
int lcs_len(char * a, int lena, char *b, int lenb)
{
if (lena == 0 || lenb == 0)
return 0;
if (a[lena - 1] == b[lenb - 1])
return lcs_len(a, lena - 1, b, lenb - 1)+1;
else
return max(lcs_len(a, lena, b, lenb - 1), lcs_len(a, lena - 1, b, lenb));
}
动态规划:
int lcs_len(char *a, int lena, char *b, int lenb)
{
int *dp = (int *)malloc(sizeof(int)*(lena + 1)*(lenb + 1));
for (int i = 0; i < lena + 1; i++)
dp[i] = 0;
for (int i = 0; i < lenb + 1; i++)
dp[(lena + 1)*i] = 0;
for (int i = 1; i < lenb + 1; i++)
for (int j = 1; j < lena + 1; j++)
{
if (a[j - 1] == b[i - 1])
dp[i*(lena + 1) + j] = dp[(i - 1)*(lena + 1) + j - 1]+1;
else
dp[i*(lena + 1) + j] = max(dp[(i - 1)*(lena + 1) + j], dp[(i)*(lena + 1) + j - 1]);
}
return dp[(lenb)*(lena+1)+lena];
}
浙公网安备 33010602011771号