动态规划:字符串编辑距离

动态规划:字符串编辑距离

问题描述

有两个字符串A和B,现在将A经过三种变换可以得到B,即插入、删除和修改,这三种操作的代价分别为c0,c1和c2,问题就是A到B的变换所需要的最小代价是多少。

思路

典型的动态规划问题,娇哥曾经说过,字符串的问题大部分都是动态规划的问题,那么这个问题要怎么解决呢?动态规划问题首先定义状态,然后定义状态转移方程,然后确定初始状态和终止状态,然后就可以得到终止状态下的结果输出。

定义状态

我们定义状态dp[i][j]表示A从0-i和B从0-j这两段的最小编辑距离。状态的定义需要注意的是,状态只能和前面的情况有联系不能和后面的情况有联系。

转移方程

有了状态,那么就定义状态转移方程,状态转移方程的定义有时候会需要“找规律”,但是这道题的规律比较明显,很容易知道,当A[i] == B[j]的时候,从dp[i-1][j-1]dp[i][j]是不需要任何编辑的,所以dp[i-1][j-1] = dp[i][j],但是当他们不相等的时候,就需要考虑是插入、删除还是编辑的代价最短了,那么自然而然地有三种情况:插入,删除和编辑。插入的情况是什么?

  • 插入是A在和B的前j-1个比,然后再在A的基础上进行插入一个字符,插入的字符是B的第j位,所以插入的代价是dp[i][j-1]+c0

  • 删除是A的前i-1个和B的j个比,因为把A删除了一个字符,所以删除的代价是dp[i-1][j]+c1

  • 编辑是A的前i-1个和B的j-1个比,然后把A的第i位变成B的第j位。所以编辑的代价是dp[i-1][j-1]+c2

    d p [ i ] [ j ] = { d p [ i − 1 ] [ j − 1 ] i f A [ i − 1 ] = = B [ j − 1 ] m i n ( m i n ( d p [ i − 1 ] [ j ] + c 1 , d p [ i − 1 ] [ j − 1 ] + c 2 ) , d p [ i ] [ j − 1 ] + c 0 ) o t h e r } dp[i][j]= \begin{Bmatrix} dp[i-1][j-1] & ifA[i-1]==B[j-1] \\\\min(min(dp[i-1][j]+c1,dp[i-1][j-1]+c2),dp[i][j-1]+c0) & other \end{Bmatrix} dp[i][j]=dp[i1][j1]min(min(dp[i1][j]+c1,dp[i1][j1]+c2),dp[i][j1]+c0)ifA[i1]==B[j1]other

代码

有了状态转移方程,代码就很好写了。代码如下

#include<bits/stdc++.h>
using namespace std;

class MinCost {
public:
	int findMincost(string A, int n, string B, int m, int c0, int c1, int c2) {//c0 c1 c2 分别是每种可能的代价
		vector < vector<int>>dp;
		dp.resize(n + 1, vector<int>(m + 1, 0));
		dp[0][0];
		for (int i = 1; i <= n; ++i)
			dp[i][0] = dp[i - 1][0] + c1;
		for (int j = 1; j <= m; ++j)
			dp[0][j] = dp[0][j - 1] + c0;
		for(int i=1;i<=n;++i)
			for (int j = 1; j <= m; ++j) {
				if (A[i - 1] == B[j - 1])
					dp[i][j] = dp[i - 1][j - 1];
				else
					dp[i][j] = min(min(dp[i - 1][j] + c1, dp[i - 1][j - 1] + c2), dp[i][j - 1] + c0);
			}
		return dp[n][m];	
	}
};

int main() {
	string s1, s2;

	s1 = "abc";
	s2 = "adc";
	MinCost M;
	cout << M.findMincost(s1, s1.size(), s2, s2.size(), 0, 3, 2) << endl;

	return 0;
}

你可能感兴趣的:(算法)