hdu1516 朴素dp

Levenshtein 距离(字符串距离)

s为初始,t为目标

1、初始化

在i等于0时,说明s串没有数据,直接一位一位插入数据。

在j等于0时,需要s串一步一步删除数据。

for(int i=0;i<=n;i++)

        dp[i][0]=i;

for(int i=0;i<=m;i++)

        dp[0][i]=i;

2、转移方程

要求dp[i][j],需要dp[i-1][j],dp[i][j-1],dp[i-1][j-1]

转移方式有三种:

1)增加:s[1…i] 转换为 t[1…j-1],由于t[j]的加入,s串也需要加上t[j],所以dp[i][j]=dp[i][j-1]+1;

2)删除:s[1..i-1]转换为t[1..j],直接删去s[i],所以dp[i][j]=dp[i-1][j]+1;

3)s[1…i-1] 转换为 t [1…j-1],

  直接比较s[i]和t[j],如果相等,dp[i][j]=dp[i-1][j-1];

  替换:如果不相等,s串的s[i]改为t[j],dp[i][j]=dp[i-1][j-1]+1;

所以dp[i][j]最终结果是三者最小的

for(int i=1;i<=n;i++)

    for(int j=1;j<=m;j++){

        dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1;

        dp[i][j]=min(dp[i][j],dp[i-1][j-1]+(s[i-1]!=t[j-1]));

    }

完整代码

import java.util.Scanner;

public class Main{
    static String s1,s2;
    static int[][] dp;
    static int n,m;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            s1=sc.next();
            s2=sc.next();
            n=s1.length();
            m=s2.length();
            dp=new int[n+1][m+1];
            inspect();
            change();
        }

    }

    private static void inspect() {
        for (int i = 0; i <= n; i++) {
            dp[i][0]=i;
        }
        for (int i = 0; i <= m; i++) {
            dp[0][i]=i;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                int ij=1;
                if(s1.charAt(i-1)== s2.charAt(j-1)){
                    ij=0;
                }
                dp[i][j]=Min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+ij);
            }
        }
        System.out.println(dp[n][m]);
    }

    private static void change() {
        int i=s1.length();
        int j=s2.length();
        int step=1;
        int temp;
        while(i>=1||j>=1){
            if(i>0&&j>0&&s1.charAt(i-1)==s2.charAt(j-1))
                temp=0;
            else
                temp=1;
            /*
                若是两个字符串中对应字母相等由于没有进行任何操作只用将上一对的数据迁移便好
                若是不相等且所有周边数据中dp[i-1][j-1]最小,那么就意味着进行了替换操作
                由于仅将这一对字母替换操作数加一所以只用将上一对字母对应数据加一赋给当前便好
             */
            if(i>=1&&j>=1&&dp[i][j]==dp[i-1][j-1]+temp){

                if(temp==1)
                    System.out.println(step+++" Replace "+i+","+s2.charAt(j-1));
                i--;
                j--;
            }
            /*
                插入原理与删除类似,因为要插入说明此时y对应的字母与x序列无关,所以
                此时操作数dp[i][j]应与dp[i][j-1]有关(x中前i个元素组成序列,与y前j-1元素序列代表的操作数)
             */
            else if(j>0&&dp[i][j]==dp[i][j-1]+1){
                System.out.println(step+++" Insert "+(i+1)+","+s2.charAt(j-1));
                j--;
            }
            /*
                此种情况代表删除
                删除操作的数据,应与{x1...x(i-1)}与{y1...y(j-1)}有关,因为删除就意味着当前
                x序列中的xi与此时的y序列无关,而x序列前i-1项是已经进行完所有操作对于x转为y有
                最短的距离,所以此时操作数dp[i][j]应与dp[i-1][j]有关,而且因为做了删除操作所以操作数加一
             */
            else if(i>0&&dp[i][j]==dp[i-1][j]+1){
                System.out.println(step+++" Delete "+i);
                i--;
            }
        }

    }

    private static int Min(int i, int i1, int i2) {
        int min=i;
        if(i1<min)
            min=i1;
        if(i2<min)
            min=i2;
        return min;

    }

}

 

posted @ 2020-07-17 09:16  BlueValentines  阅读(95)  评论(0)    收藏  举报