求最长公共子序列长度 (递归、动态规划)

所谓子序列,是指从序列中任意取出元素,按原序列中的顺序排序得到的序列。
所谓序列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];
}
posted @ 2022-04-19 18:17  enbug  阅读(156)  评论(0)    收藏  举报