动态规划——最长公共子串

引入:

最长公共子序列常用于解决字符串的相似度问题。

最长公共子序列(Longest Common Subsequence,LCS)与最长公共字串(Longest Common Substring):子串是串的一个连续的部分,子序列则是从不改变序列顺序,而从序列中去掉任意多个元素而获得的新的序列;也就是说,子串中字符的位置一定是连续的,而子序列不一定连续。

a  not the 之一(得到的未必就是唯一的那个最长公共子串,只有长度是唯一的)

——其余字符串问题,待续

解决方案:

1、穷举法(Bruke force alg )

a[m] and b[n]

check every sequence of a ,to see if it is a sequence of b .

analysis:

check = O(N)

2^m subsequence of a

so O(n*2^m)=slow

不可取:一个长度为N的字符串,其子序列有2^N个,指数级的复杂度。

2、递归法

对于字符串a[ ]和 b[ ],当a与b位置上的字符相同时,则直接求解下一个位置,当不同时取两种情况下较大的数值。

 1 #include<stdio.h>
2
3 #include<string.h>
4
5 char a[30],b[30];
6
7 int lena,lenb;
8
9 int LCS(int,int);  ///两个参数分别表示数组a的下标和数组b的下标
10
11 int main()
12
13 {
14
15 strcpy(a,"ABCBDAB");
16
17 strcpy(b,"BDCABA");
18
19 lena=strlen(a);
20
21 lenb=strlen(b);
22
23 printf("%d\n",LCS(0,0));
24
25 return 0;
26
27 }
28
29 int LCS(int i,int j)
30
31 {
32
33 if(i>=lena || j>=lenb)
34
35 return 0;
36
37 if(a[i]==b[j])
38
39 return 1+LCS(i+1,j+1);
40
41 else
42
43 return LCS(i+1,j)>LCS(i,j+1)? LCS(i+1,j):LCS(i,j+1);
44
45 }

代码实现

优点:容易理解,编程简单,

缺点:效率低下,有大量重复执行的递归调用,且只能求出最大公共子序列的长度,不能得到具体的公共子序列。

3、动态规划

改进:采用二维数组来标记中间结果,避免重复的计算以便提高效率。

对于字符串a[]和 b[],num[i][j]记录序列a[ i]和 b[j ]的最长公共子序列的长度,其中,a[ i]即{a1,a2,....,ai}和 b[j ]即{b1,b2,....,bj}

b[i][j]来记录c[i][j]的值是由哪一个子问题的解得到的。

  1 #include<stdio.h>
2
3 #include<string.h>
4
5
6
7 char a[500],b[500];
8
9 char num[501][501]; ///记录中间结果的数组
10
11 char flag[501][501]; ///标记数组,用于标识下标的走向,构造出公共子序列
12
13 void LCS(); ///动态规划求解
14
15 void getLCS(); ///采用倒推方式求最长公共子序列
16
17
18
19 int main()
20
21 {
22
23 int i;
24
25 strcpy(a,"ABCBDAB");
26
27 strcpy(b,"BDCABA");
28
29 memset(num,0,sizeof(num));
30
31 memset(flag,0,sizeof(flag));
32
33 LCS();
34
35 printf("%d\n",num[strlen(a)][strlen(b)]);
36
37 getLCS();
38
39 return 0;
40
41 }
42
43
44
45 void LCS()
46
47 {
48
49 int i,j;
50
51 for(i=1;i<=strlen(a);i++)
52
53 {
54
55 for(j=1;j<=strlen(b);j++)
56
57 {
58
59 if(a[i-1]==b[j-1]) ///注意这里的下标是i-1与j-1
60
61 {
62
63 num[i][j]=num[i-1][j-1]+1;
64
65 flag[i][j]=1; ///斜向下标记
66
67 }
68
69 else if(num[i][j-1]>num[i-1][j])
70
71 {
72
73 num[i][j]=num[i][j-1];
74
75 flag[i][j]=2; ///向右标记
76
77 }
78
79 else
80
81 {
82
83 num[i][j]=num[i-1][j];
84
85 flag[i][j]=3; ///向下标记
86
87 }
88
89 }
90
91 }
92
93 }
94
95
96
97 void getLCS()
98
99 {
100
101
102
103 char res[500];
104
105 int i=strlen(a);
106
107 int j=strlen(b);
108
109 int k=0; ///用于保存结果的数组标志位
110
111 while(i>0 && j>0)
112
113 {
114
115 if(flag[i][j]==1) ///如果是斜向下标记
116
117 {
118
119 res[k]=a[i-1];
120
121 k++;
122
123 i--;
124
125 j--;
126
127 }
128
129 else if(flag[i][j]==2) ///如果是斜向右标记
130
131 j--;
132
133 else if(flag[i][j]==3) ///如果是斜向下标记
134
135 i--;
136
137 }
138
139
140
141 for(i=k-1;i>=0;i--)
142
143 printf("%c",res[i]);
144
145 }
146
147

代码实现

动态规划——最长公共子串,码迷,mamicode.com

时间: 2024-10-23 00:25:58

动态规划——最长公共子串的相关文章

算法作业6 动态规划 - 最长公共子串问题

问题描述:Given 2 sequences, X = x1,...,xm and Y = y1,...,yn, find a common subsequence whose length is maximum. Subsequence need not be consecutive, but must be in order. 程序思路: 使用递归的思路可以解决这个问题.设输入的两个子串为X[0…m - 1]和Y[0…n - 1],L(X[0…m - 1], Y[0…n - 1])为X和Y的

动态规划--最长公共子串

最长公共子串也是一个动态规划的问题,先求出子问题的解,然后才能求出最优解. 首先我们来看设X = <x1, x2, ..., xm>, Y= <y1, y2, ..., yn>,设C[i][j]为串 Xi 和 Yj 的最长公共子串长度,则 C[i][j]  =  C[i-1][j-1] +1,  Xi == Yj C[i][j]  =  0,  Xi != Yj 申请一个m*n的数组,同时计算出该数组对应位置的数值,找出最大值,则为X 和 Y最长公共子串. 代码如下: 1 // L

动态规划 &amp; 最长公共子串算法(LCS)

求最长公共子串可以先求最长公共子串的长度,并且记录那些公共子串字符的长度以及字符,然后通过回溯可以找到所有的公共子串. 下面是求最长公共子串长度的动态规划方法. 1:决策,我们在最后一步需要做的决策是,是否要将A[n],B[m]加入公共子串序列中. 2:由 1 可知,若以DP[i][j]表示A[1..i] 与 B[1..j]的最长公共子串的长度,那么可以得到 (1) 若A[i] == B[j]  (即作出决策,将A[i],B[i]都加入公共子串) DP[i][j] = DP[i - 1][j -

[程序员代码面试指南]递归和动态规划-最长公共子串问题

题目描述 给定两个串,输出最长公共子串. 解题思路 维护dp[i][j],表示子串str1[0:i+1]与str2[0:j+1]的最长公共子串长度. 由dp[][]右下角开始,找公共子串. 代码 public class Solution{ private int[][] getDp(char[] str1,char[] str2){ int[][] dp=new int[str1.length][str2.length]; int temp=0; for(int i=0;i<str1.leng

动态规划之最长公共子串

一 问题引入 在生物学中,经常需要比较两个不同生物的DNA,一个DNA串由由一串称为碱基的的分子组成,碱基有鸟嘌呤,腺嘌呤,胞嘧啶,胸腺嘧啶四中,我们用英文字母的首字母表示四种碱基,那么DNA就是在有限集{A,C,G,T}上的一个字符串.例如某种生物的DNA序列为:S1=ACCGGTCGAGTGCGCGGAAGCCGGCCGAA,S2=GTCGTTCGGAATGCCGTTGCTCTGTAAA,我们比较两个DNA串的原因就是希望确定他们的相似度,作为衡量两个物种相似度的标准.如果一个串是另外一个串

动态规划算法之:最长公共子序列 & 最长公共子串(LCS)

1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab") b a b c 0 0 0 a 0 1

《算法导论》读书笔记之动态规划—最长公共子序列 &amp; 最长公共子串(LCS)

From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是

java 动态规划算法求解最长公共子串

最近在项目中碰到了这样的一个问题,要比较JS和CSS是否做了修改,先是想着借助第三方工具发现没找到,后面转念一想,这个问题不就是对两个文件的第一行求最大的公共子串嘛,既然是要求公共子串的最大长度,由此想到了动态规划算法. 代码是从网上C++改写过来的,感谢那位C++的兄弟,代码如下: package dp; /** * 用动态规划算法求解 最长公共子串 * @author * */ public class LCSSuffix { private static String getLCSLeng

求两个字符串最长公共子串(动态规划)

code如下: //Longest common sequence, dynamic programming method void FindLCS(char *str1, char *str2) { if(str1 == NULL || str2 == NULL) return; int length1 = strlen(str1)+1; int length2 = strlen(str2)+1; int **csLength,**direction;//two arrays to recor