zoukankan      html  css  js  c++  java
  • 动态规划-最长公共子序列长度/最长公共子串/最小编辑代价

    (一)最长公共子序列

     

    对于两个字符串,请设计一个高效算法,求他们的最长公共子序列的长度,这里的最长公共子序列定义为有两个序列U1,U2,U3...Un和V1,V2,V3...Vn,其中Ui&ltUi+1,Vi&ltVi+1。且A[Ui] == B[Vi]。

    给定两个字符串AB,同时给定两个串的长度nm,请返回最长公共子序列的长度。保证两串长度均小于等于300。(子序列可以是不连续的)

    测试样例:
    "1A2C3D4B56",10,"B1D23CA45B6A",12
    返回:6

    1)如果 xn=ym,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(Xn-1,Ym-1)

    LCS(Xn-1,Ym-1)就是原问题的一个子问题。为什么叫子问题?因为它的规模比原问题小。(小一个元素也是小嘛....)

    为什么是最优的子问题?因为我们要找的是Xn-1 和 Ym-1 的最长公共子序列啊。。。最长的!!!换句话说,就是最优的那个。(这里的最优就是最长的意思)

    2)如果xn != ym,这下要麻烦一点,因为它产生了两个子问题:LCS(Xn-1,Ym) 和 LCS(Xn,Ym-1)

    因为序列X 和 序列Y 的最后一个元素不相等嘛,那说明最后一个元素不可能是最长公共子序列中的元素嘛。(都不相等了,怎么公共嘛)。

    LCS(Xn-1,Ym)表示:最长公共序列可以在(x1,x2,....x(n-1)) 和 (y1,y2,...yn)中找。

    LCS(Xn,Ym-1)表示:最长公共序列可以在(x1,x2,....xn) 和 (y1,y2,...y(n-1))中找。

    求解上面两个子问题,得到的公共子序列谁最长,那谁就是 LCS(X,Y)。用数学表示就是:

    LCS=max{LCS(Xn-1,Ym),LCS(Xn,Ym-1)}

    状态转移方程为:

    建立一个(n+1)(m+1)维数组存放公共子序列的长度。

    class LCS {
    public:
        int findLCS(string A, int n, string B, int m) {
            // write code here
            int dp[301][301];
            for(int i=0;i<=n;++i){
                dp[i][0]=0;
            }
            for(int j=0;j<=m;++j){
                dp[0][j]=0;
            }
            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]+1;
                    }
                    else{
                        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                    }
                }
                
            }
            return dp[n][m];
            
        }
    };
    

     (二)最长公共子串

    上面最长公共子序列要求是不连续的,而最长公共子串要求是连续的,差别就在状态方程的变化:

    当A[i]==B[j],dp[i][j]=dp[i-1][j-1]+1;当A[i]!=B[i]时,dp[i][j]=0

    class LongestSubstring {
    public:
        int findLongest(string A, int n, string B, int m) {
            // write code here
            int maxLen=0;
            int dp[301][301];
            for(int i=0;i<=n;++i){
                dp[i][0]=0;
            }
            for(int j=0;j<=m;++j){
                dp[0][j]=0;
            }
            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]+1;
                        
                    } else {
                        dp[i][j] = 0;
                    }
                    maxLen = max(maxLen, dp[i][j]);
                }
            }
             return maxLen;
        }
       
    };

     (三)最小编辑代价

    链接:https://www.nowcoder.com/questionTerminal/04f1731f32e246b4a19688972d5e2600 来源:牛客网

    对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。

    给定两个字符串AB,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。

    测试样例:
    "abc",3,"adc",3,5,3,100
    返回:8

    思路与之前类似,也是建立一个(n+1)(m+1)辅助数组,因为要把A字符串变为B字符串,当j=0时(说明B字符串为空),每一行的代价为删除代价,代价为i*c1;当i=0时,每一列的代价为插入代价,代价为j*c0。

    1)修改=删除+插入 c2=min(c2,c0+c1)

    2)当两个数相等时dp[i][j]=dp[i-1][j-1]

    2)当两个数不相等时,有三种不同情况dp[i-1][j]+c1, dp[i][j-1]+c0, dp[i-1][j-1]+c2;

    代码如下:

    class MinCost {
    public:
        int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
            // write code here
            int dp[301][301];
            for(int i=0;i<=n;++i){
                dp[i][0]=i*c1;
            }
            for(int j=0;j<=m;++j){
                dp[0][j]=j*c0;
            }
            c2=min(c2,c0+c1);
            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(dp[i-1][j-1]+c2,min(dp[i-1][j]+c1,dp[i][j-1]+c0));
                    }
                }
            }
            return dp[n][m];
        }
    };
  • 相关阅读:
    kernel structure
    linux cmd fuser/screen
    arm 指令架构
    udev 学习
    grup 2 ubuntu
    tiny6410 3.8.1 内核kgdb调试
    make 选项
    lfs 无知
    数据归一化的两种方法:最值归一化和0均值归一化
    使用随机队列实现生成迷宫
  • 原文地址:https://www.cnblogs.com/rgly/p/7573806.html
Copyright © 2011-2022 走看看