最长公共子序列和最长公共子串

动态规划与分治法之间的区别:
1.divide and conquer algorithm分治法是指将问题分成一些独立的子问题,递归的求解各子问题。
2.dynamic programming algorithm动态规划适用于这些子问题不是独立的情况,也就是各子问题包含公共子问题。

最长公共子序列和最长公共子串的区别:
找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的;而最长公共子序列则并不要求连续。

最长公共子序列: LCS(Longest Common Subsequence)

DP动态规划方程


回溯输出最长公共子序列过程:

构建c[i][j]表需要Θ(mn),输出1个LCS的序列需要Θ(m+n)。
算法:
LCS-LENGTH(X,Y)
    m=X.length
    n=Y.length
    let b[1..m,1..n] and c[0..m,0..n] be new tables
    for i=1 to m
        c[i,0]=0
    for j=1 to n
        c[0,j]=0
    for i=1 to m
        for j=1 to n
            if xi==yj
                c[i,j]=c[i-1,j-1]+1
                b[i,j]=0 //xi=yi,是LCS的一个元素
            elseif c[i-1,j]>=c[i,j-1]
                c[i,j]=c[i-1,j]
                b[i,j]=1 //向上前进
            else c[i,j]=c[i,j-1]
                b[i,j]=-1 //向左前进
    return c and b

PRTNT-LCS(b,X,i,j)
    if i==0 or j==0
        return
    if b[i,j]==0
        PRINT-LCS(b,X,i-1,j-1)
        print xi
    elseif b[i,j]==1;
        PRINT-LCS(b,X,i-1,j)
    else PRINT-LCS(b,X,i,j-1)
最长公共子串(Longest Common Substring)
DP方程
  c[0,j]=0;
  c[i,0]=0;
  c[i,j]=c[i-1,j-1]+1 if x[i]==y[j];
  c[i,j]=0 if x[i]!=y[j];
  最大子串长度max=max{c[i][j]}

完整的代码
#include <stdio.h>
#include <string.h>
#define MAXLEN 100

//DP

void lcslength(char x[], char y[], int m, int n, int c[][MAXLEN], int b[][MAXLEN])
{
	int i, j;

	for (i = 0; i <= m; i++)
		c[i][0] = 0;
	for (j = 1; j <= n; j++)
		c[0][j] = 0;
	for (i = 1; i <= m; i++)
	{
		for (j = 1; j <= n; j++)
		{
			if (x[i - 1] == y[j - 1])
			{
				c[i][j] = c[i - 1][j - 1] + 1;
				b[i][j] = 0; //in LCS
			}
			else if (c[i - 1][j] >= c[i][j - 1])
			{
				c[i][j] = c[i - 1][j];
				b[i][j] = 1; //up
			}
			else
			{
				c[i][j] = c[i][j - 1];
				b[i][j] = -1; //left
			}
		}
	}
}

void printlcs(int b[][MAXLEN], char *x, int i, int j)
{
	if (i == 0 || j == 0)
		return;
	if (b[i][j] == 0)
	{
		printlcs(b, x, i - 1, j - 1);
		printf("%c ", x[i - 1]);
	}
	else if (b[i][j] == 1)
		printlcs(b, x, i - 1, j);
	else
		printlcs(b, x, i, j - 1);
}

void longestcommonsubstring(char x[], char y[], int m, int n, int c[][MAXLEN]) {
	int i, j;
	int k, xpos, max;
	max = -1;

	//length
	for (i = 0; i <= m; i++)
		c[i][0] = 0; //第0列都初始化为0
	for (j = 1; j <= n; j++)
		c[0][j] = 0; //第0行都初始化为0
	for (i = 1; i <= m; i++)
	{
		for (j = 1; j <= n; j++)
		{
			if (x[i - 1] == y[j - 1])
				c[i][j] = c[i - 1][j - 1] + 1;
			else
				c[i][j] = 0;
			if (c[i][j] > max) {
				max = c[i][j];
				xpos = i;
			}
		}
	}
	//print
	char lcs[MAXLEN] = {};
	for (i = xpos - 1, k = max - 1; k >= 0; k--, i--)
		lcs[k] = x[i];

	printf("%s\n", lcs);
}


int main(int argc, char **argv)
{
	char x[MAXLEN] = { "ABCBDABIXYZJ" };
	char y[MAXLEN] = { "BDCABAKXYZW" };
	int b[MAXLEN][MAXLEN] = {};
	int c[MAXLEN][MAXLEN] = {};
	int d[MAXLEN][MAXLEN] = {};
	int m, n;

	m = strlen(x);
	n = strlen(y);

	printf("Longest Common Subsequence: ");
	lcslength(x, y, m, n, c, b);
	printlcs(b, x, m, n);
	printf("\n");

	printf("Longest Common Substring: ");
	longestcommonsubstring(x, y, m, n, d);
	printf("\n");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值