最短编辑距离

题目

分析

 

根据最长公共子序列中状态表示的技巧,本题依旧两个串。状态标识设 dp[i,j] 表示将a[1-i] 变为 b[1-j] 的所有操作方式的集合中最少操作次数。

其实做了几道线性dp的题目,发现还是有些技巧:就是大都根据最后一个状态或者最后一个或一对元素考虑

递推公式的推导:考虑元素a[i] 和 b[j]的三种操作

1. 通过删除a[i] 使得 a[1-i] 变为 b[1-j],意味着a[1-i-1]与b[1-j]已经匹配 。

  dp[i,j] = dp[i-1,j]  + 1

2. 通过对a数组增加元素使得  a[1-i+1] 变为 b[1-j],意味着a[1-i]与b[1-j-1]已经匹配 

  dp[i,j] = dp[i,j-1]  + 1

3.通过修改a[i]使得  a[1-i] 变为 b[1-j],意味着[1-i-1]与b[1-j-1]已经匹配 

  dp[i,j] = dp[i,j-1]  + (1/0)       若a[i] == b[j] 则不用加1,若不等则需要改a[i],加1

最终 dp[i][j] = min(dp[i-1,j]  + 1, dp[i,j-1]  + 1,dp[i,j-1]  + (1/0)   

代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<climits>
 4 using namespace std;
 5 
 6 const int N = 1010;
 7 char a[N],b[N];
 8 int dp[N][N];
 9 int main(){
10     int n,m;
11     scanf("%d%s",&n,a+1);
12     scanf("%d%s",&m,b+1);
13     //边界初始化 
14     //若a数组0个元素,则a只能添加操作
15     for(int i = 0;i <= m;i++) dp[0][i] = i;
16     //若b数组0个元素,则a只能删除操作
17     for(int i = 0;i <= n;i++) dp[i][0] = i;
18     
19     for(int i = 1;i <= n;i++){
20         for(int j = 1;j <= m;j++){
21             dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + 1;
22             if(a[i] == b[j]){
23                 dp[i][j] = min(dp[i][j],dp[i-1][j-1]);
24             }
25             else{
26                 dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);
27             }
28                 
29         }
30     }
31     printf("%d",dp[n][m]);
32     return 0;
33 }

注意边界条件!!!第0行或第0列并不一定全为0!!!

时间复杂度O(N2)

posted @ 2021-02-18 17:23  Uitachi  阅读(48)  评论(0编辑  收藏  举报