求字符串編輯距離

這道題,我在阿里巴巴面試的時候碰到了,google的筆試題。。。html


設A和B是2個字符串。要用最少的字符操做將字符串A轉換爲字符串B。這裏所說的字符操做包括:ios

(1)刪除一個字符;
(2)插入一個字符;
(3)將一個字符改成另外一個字符。
將字符串A變換爲字符串B所用的最少字符操做數稱爲字符串A到B的編輯距離,記爲d(A,B)。試設計一個有效算法,對任給的2個字符串A和B,計算出它們的編輯距離d(A,B)。
面試

方法1:編程之美的遞歸方法算法

 

#include <iostream>
#include <string>
using namespace std;

int Min(int a,int b,int c)
{
	int t = a<b?a:b;
	return t<c?t:c;
}

int CalDistance(const string &strA,int pAbegin,int pAend,
				const string &strB,int pBbegin,int pBend)
{
	if(pAbegin>pAend){
		if(pBbegin>pBend)return 0;
		else return pBend-pBbegin+1;
	}
	if(pBbegin>pBend){
		if(pAbegin>pAend)return 0;
		else return pAend-pAbegin+1;
	}
	if(strA[pAbegin] == strB[pBbegin]){
		return CalDistance(strA,pAbegin+1,pAend,strB,pBbegin+1,pBend);
	}
	else{
		int disa = CalDistance(strA,pAbegin+1,pAend,strB,pBbegin+1,pBend) + 1;//替換
		int disb = CalDistance(strA,pAbegin,pAend,strB,pBbegin+1,pBend) + 1;//a插入
		int disc = CalDistance(strA,pAbegin+1,pAend,strB,pBbegin,pBend) + 1;//b插入
		return Min(disa,disb,disc);
	}
}
int main()
{
	string strA = "lsjd";
	string strB = "ls";
	cout<<CalDistance(strA,0,strA.size()-1,strB,0,strB.size()-1)<<endl;
	system("pause");
	return 0;
}

上面這種方法有個缺點:遞歸樹上有重複計算的節點。咱們能夠經過備忘錄的方法來記錄一些值,從而下降重複計算。編程

 


方法2:動態規劃解法
ui

  總結個經驗:像這種從後面由前面推(自頂向下)均可以轉換爲動態規劃算法(自底向上)。包括本博客上:斐波拉契序列,徹底揹包問題,撈魚問題。google

 

    咱們能夠得出這樣一段動態規劃公式:(下面的內容引自:http://qinxuye.me/article/get-edit-distance-by-dynamic-programming/;http://blog.chinaunix.net/uid-20761674-id-75042.htmlspa

  (1)若是i == 0 且 j == 0,edit(i, j)=0.net

  (2)若是i == 0 且 j > 0,edit(i, j)=j設計

  (3)若是i > 0 且j == 0,edit(i, j)=i(二、3點以前已經陳述)

  (4)若是0 < i≤1  且 0 < j ≤ 1 ,edit(i, j) == min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1,j-1)+ f(i, j) },這裏當字符串1的第i個字符不等於字符串2的第j個字符時,f(i, j) = 1;不然,f(i, j) = 0。

  (5)若是i > 1且 j > 1時,這個時候可能出現操做(4),由以前的推導,咱們只能交換一次,不然就沒有意義。這個時候在比較最小值中可能加入edit(i-2, j-2) +1,何時加入呢?假設i-2長度的字符串1子串和j-2長度的字符串2子串已經得出最優解,這個時候若是s1[i-1] == s2[j] 而且s1[i] == s2[j-1],這時就在比較值中加入edit(i-2, j-2) + 1(這個1是交換一次的操做)

     即最後的遞推公式:首先給定第一行和第一列,而後,每一個值d[i,j]這樣計算:d[i][j]   =   min(d[i-1][j]+1,d[i][j-1]+1,d[i-1][j-1]+(s1[i] ==  s2[j]?0:1));   

 代碼:

 

#include <stdio.h>   
#include <string.h>   
char s1[1000],s2[1000];   
int min(int a,int b,int c) {   
    int t = a < b ? a : b;   
    return t < c ? t : c;   
}   
void editDistance(int len1,int len2) {   
    int d[len1+1][len2+1];   
    int i,j;   
    for(i = 0;i <= len1;i++)   
        d[i][0] = i;   
    for(j = 0;j <= len2;j++)   
        d[0][j] = j;   
    for(i = 1;i <= len1;i++)   
        for(j = 1;j <= len2;j++) {   
            int cost = s1[i] == s2[j] ? 0 : 1;   
            int deletion = d[i-1][j] + 1;   
            int insertion = d[i][j-1] + 1;   
            int substitution = d[i-1][j-1] + cost;   
            d[i][j] = min(deletion,insertion,substitution);   
        }   
    printf("%d\n",d[len1][len2]);   
}
相關文章
相關標籤/搜索