当给的两个字符串没有一个对应位置上的字符是相等的话,那么如果从str1转换为str2,也就相当于一个空白的字符串转换为其中任意一个字符串
如果在我们枚举的区间[ 0 , i ]中第i个字符是相同的,那么实质上这里就和我们直接更新区间 [ 0 , i-1 ]是相同的,这样的话,我们也只是可以更新开头位置必须为0的相应区间
但是当我们中间存在相应位置字符相同的话,我们可以枚举中间某个位置k,寻找最优解(最终得到的位置就是在[k+1,i]区间中,没有和str1中相同的字符),并且一定会得到最终的最优解
算法解释
首先是将一个空白字符串转换为str2:dp[i][j] :表示在区间[i , j] 中最少的转变次数,我们可以简单的想到 :dp[i][j] = dp[i][k-1] + dp[k][ j] ,但是当str2[i] == str2[k]时,这个式子还是可以优化的,所以上面这个式子就是不对的,而是:
if(str2[i] == str[k]) dp[i][j] = min( dp[i][j] , dp[i+1][k-1] + dp[k][j])
那么剩下的就类似石子归并的区间DP了,程序如下:
for(int len = 2;len <= n;len ++) //首先我们先求出将空白串转换成str2需要的次数,这里实质可以使用石子归并的模板 { for(int i = n-len+1;i >=0 ;i --)//起点 { int j = i+len-1;//终点 dp[i][j] = dp[i+1][j] + 1;//初始值设置 for(int k = i+1;k<=j;k ++)//寻找中间位置,只有和开头位置相同的时候,我们就可以优化一次,因为相同的话,我们就可以将其分成两部分! if(str2[i] == str2[k]) dp[i][j] = min(dp[i][j],dp[i+1][k-1]+dp[k][j]); } }
剩下的就是我们的转化过程了,ans[i]: [0,i]区间 由 str2 转换为 str1 需要的最少次数,那么ans初始化为 ans[i] = dp[0][i]
当str1[i] == str2[i]时,ans[i] = ans[i-1],如果不相等的话,我们就要去进行上面第三步骤更新,具体请看程序:
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; const int MAXN=110; int dp[MAXN][MAXN]; char str1[MAXN],str2[MAXN]; int ans[MAXN]; int main() { while(scanf("%s%s",str1,str2)==2) { int n=strlen(str1); memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++) for(int j=i;j<n;j++) dp[i][j]=j-i+1;//dp[i][j]现在存储的是 i~j 最多变换的次数,也就是他的长度 for(int len = 2;len <= n;len ++) //首先我们先求出将空白串转换成str2需要的次数,这里实质可以使用石子归并的模板 { for(int i = n-len+1;i >= 0 ;i --)//起点 { int j = i+len-1;//终点 dp[i][j] = dp[i+1][j] + 1;//初始值设置 for(int k = i+1;k<=j;k ++)//寻找中间位置,只有和开头位置相同的时候,我们就可以优化一次,因为相同的话,我们就可以将其分成两部分! if(str2[i] == str2[k]) dp[i][j] = min(dp[i][j],dp[i+1][k-1]+dp[k][j]); } } ///ans[i]:0~i 由str2转换为str1需要的最少次数 ///从str2转换为str1,这里如果对应相等的话,次数就等于前一个,因为这个位置不用重新转换 for(int i=0;i<n;i++) { ans[i]=dp[0][i]; if(str1[i]==str2[i])//当对应的位置相同时 { if(i==0)ans[i]=0;//第一个位置时 else ans[i]=ans[i-1];//否则等于前面位置转换的步数,如果一直相等就会一直等于前一个 } else { for(int j=0;j<i;j++)//如果中间的情况有相等的情况下,枚举中间的点,取最小值 ans[i]=min(ans[i],ans[j]+dp[j+1][i]); } } printf("%d\n",ans[n-1]); } return 0; }