1. 程式人生 > >動態規劃求解兩個字串的最大公共子串問題

動態規劃求解兩個字串的最大公共子串問題

最大公共子串長度問題就是:
求兩個串的所有子串中能夠匹配上的最大長度是多少。

比如:"abcdkkk" 和 "baabcdadabc",
可以找到的最長的公共子串是"abcd",所以最大公共子串長度為4。

下面的程式是採用矩陣法進行求解的,這對串的規模不大的情況還是比較有效的解法。

請分析該解法的思路,並補全劃線部分缺失的程式碼。

#include <stdio.h>
#include <string.h>

#define N 256
int f(const char* s1, const char* s2)
{
	int a[N][N];
	int len1 = strlen(s1);
	int len2 = strlen(s2);
	int i,j;
	
	memset(a,0,sizeof(int)*N*N);
	int max = 0;
	for(i=1; i<=len1; i++){
		for(j=1; j<=len2; j++){
			if(s1[i-1]==s2[j-1]) {
				a[i][j] = __________________________;  //填空
				if(a[i][j] > max) max = a[i][j];
			}
		}
	}
	
	return max;
}

int main()
{
	printf("%d\n", f("abcdkkk", "baabcdadabc"));
	return 0;
}

【分析】DP

        這裡使用動態規劃法求解串s1和s2的最大公共子串長度,a[i][j]表示串s1的前i個字元組成的串和串s2的前j個字元組成的串的最大公共子串的長度。

       s1中的子串s1[0]..s1[i]匹配s2中的子串s2[0]..s2[j],在s1[0]..s1[i-1]和s2[0]..s2[j-1]已經匹配的情況下匹配長度+1,即a[i][j]=a[i-1][j-1]+1,此方程是在s1[i]和s2[j]匹配的情況下才成立的  即s1[i]==s2[j];

        而題目程式碼中給出的判斷條件是if(s1[i-1]==s2[j-1]),這是因為對於一個字串s1來說,它的子串必定"含於"s1[0]..s1[len1-1],而a陣列的下標是從1開始的,這樣做的好處是不需要進行陣列邊界處理

。試想一下,如果a陣列和串s1 s2下標都從0開始,a[0][0]表示s1[0]和s2[0]匹配的情況,則在s1[0]==s2[0]的情況下必然有a[0][0]=a[0-1][0-1]+1(越界!)。解決辦法即是進行陣列邊界處理:
if(s1[i]==s2[j])
{
if(i==0||j==0) a[i][j]=1;
else a[i][j]=a[i-1][j-1]+1;
}

        此外,我們對於動態規劃求最優解應該有一個概念:最優解不一定要在狀態中表示出來。例如在這裡,我們只需要把所有子串匹配長度求出來,然後去更新最大長度就可以了。這裡的狀態並不是當前情況下的最優解。

【答案】a[i-1][j-1]+1