字串之間的最短距離

小弟季義欽發表於2012-11-11
#include <iostream>
using namespace std;

//為了方便,將a和b的長度固定下來,這樣就不用動態建立陣列了
#define M 6
#define N 3
int dp[M][N] = {0};
/**
* 問題描述: 兩個字串如果可以根據新增,刪除,修改一個字串來變成另一個字串,則
* 說這兩個字串距離為1. 現在給出兩個字串,求出他們之間的距離。
* abcehk和bdh的距離。
* 要將一個字串變成另一個,這裡假設將B變換成A,很明顯這個問題有子結構。
* 要求f(m,n),即字串A與字串B的距離:
* 如果a[m] == b[n],那麼這個距離就是其上一個狀態,即f(m-1,n-1)。
* 如果a[m] != b[n],
*	要麼刪除b[n],這個時候問題變成f(m,n-1)
*	要麼為B增加一個和a[m]相同的字元讓其與A的結尾相同,這個時候問題變成f(m,n+1) = f(m-1,n)(因為末尾字元相同,故不考慮)。
*	要麼修改b[n]為a[m],這個時候問題變成求解f(m-1.n-1).
* 這些操作的代價都是1,主要是看子問題的代價,選擇最小的。(DP特徵)
* 
* 所以我們定義狀態f(m,n)為長度為m的串A與長度為n的串B之間的距離。
* 然後定義狀態轉移方程為:
* f(m,n) = 
*	f(m-1,n-1),								a[m] == b[n]
*   min{f(m-1,n-1),f(m,n-1),f(m-1,n)}+1,	a[m]!=b[n]
* 自底向上求解,DP求解矩陣的第一行和第一列很容易初始化.
*/
int min(int x, int y, int z){
	if(x<y){
		if(x<z) return x;
		else return z;
	}
	else{
		if(y<z) return y;
		else return z;
	}
}

int getDistance(char *a, char *b){
	if(a==NULL || b==NULL) return 0;

	//初始化兩個字串的長度
	int a_len=M,b_len=N;

	//初始化第一行和第一列
	if(a[0] != b[0]) dp[0][0] = 1;
	else dp[0][0] = 0;
	
	for(int i=1;i<b_len;i++){ //第一行
		if(a[0] != b[i]) dp[0][i] = dp[0][i-1]+1;
		else dp[0][i] = dp[0][i-1];
	}
	for(int j=1;j<a_len;j++){ //第一列
		if(b[0] != a[j]) dp[j][0] = dp[j-1][0]+1;
		else dp[j][0] = dp[j-1][0];
	}

	//開始自底向上計算
	for(i=1;i<a_len;i++){
		for(j=1;j<b_len;j++){
			if(a[i] == b[j]) dp[i][j] = dp[i-1][j-1];
			else{
				dp[i][j] = min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j])+1;
			}
		}
	}

	//列印出最短距離陣列
	for(i=0;i<a_len;i++){
		for(j=0;j<b_len;j++){
			cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	}
	return dp[M-1][N-1];
}

int main(){
	
	/**
	*  注意順序,這裡a作為列,b作為行
	*/
	char *a = "abcehk";
	char *b = "beh";

	cout<<getDistance(a,b)<<endl;
	return 0;
}

相關文章