兩個字串的最長公共子串

小弟季義欽發表於2012-11-04

DP的方式求解:

#include <iostream>

using namespace std;

#define M 9
#define N 11
//如果動態傳進m和n的話,陣列lcs賦值只能通過指標,這樣太麻煩
int lcs[M][N];

/**
* 最長公共子串(LCS)
* 狀態轉移方程:
* f(i,j) = 
	0				a[i] != b[j]
	f(i-1,j-1)+1	a[i] == b[j]
	其中f(i,j)表示串A以a[i]結尾與串B以b[j]結尾的最長公共子串
* 優化: 這裡時間和空間都是O(M*N)。
*	注意到我們自底向上求解lcs[m][n]的時候,其實是
*	逐行求解的。每行只依賴於上一行的值,所以我們其實可以利用
*	“滾動陣列”來優化這個DP解法的空間到O(N)。
*/
char *lcs1(char *a, char *b){
	int a_len = M,b_len = N;
	char *p;
	int i,j;
	int max = 0, end_y;

	//初始化二位陣列的第0列
	p = a;
	for(i=0;i<a_len;i++){
		if(a[i] == b[0]) lcs[i][0] = 1;
		else lcs[i][0] = 0;
	}

	//初始化二維陣列的第0行
	p = b;
	for(j=0;j<b_len;j++){
		if(b[j] == a[0]) lcs[0][j] = 1;
		else lcs[0][j] = 0;
	}

	/**
	* 核心部分:一行一行地自底向上求解
	*/
	for(i=1;i<a_len;i++)
		for(j=1;j<b_len;j++){
			//相同,則公共長度lcs[i][j]=lcs[i-1][j-1]+1
			if(*(a+i) == *(b+j)){
				lcs[i][j] = lcs[i-1][j-1] + 1;
				
				//記錄最大長度的橫座標
				if(lcs[i][j] > max){
					max = lcs[i][j];
					end_y = i;
				}
			}
			//不同,公共長度為0
			else{
				lcs[i][j] = 0;
			}
		}

	//輸出lcs矩陣
	for(i=0;i<a_len;i++){
		for(j=0;j<b_len;j++){
			cout<<lcs[i][j];
		}
		cout<<endl;
	}

	//將公共子串(從a串中取)放入新空間並返回
	p = (char *)malloc(sizeof(char)*(max+1));
	j = 0;
	for(i = end_y-max+1;i<=end_y;i++){
		*(p+j) = a[i];
		j++;
	}
	*(p+j) = '\0';

	return p;
}

int main(){
	char *a = "ackonpbee";
	char *b = "dcaconpbexx";
	cout<<"lcs:"<<lcs1(a,b)<<endl;;

	return 0;
}

相關文章