动态规划2---最长公共子序列

动态规划2---最长公共子序列,第1张

问题描述:

字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。


令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列,使得对所有的j=0,1,…,k-1,有xij=yj。


例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。




依旧按照动态规划的五个步骤来求解此题。


1、确定dp数组以及其下标的含义。


设两个字符串为text1和text2。


用dp[i][j]来表示text1中0~i-1区间的字符串和text2中0~j-1区间的字符串的最长公共子序列,区间为闭区间,也就是索引为0的字符和索引为i-1的字符可以取到。


另外还要注意的是i-1和j-1。


2、确定动态规划方程。


情况一:当text[i-1]=text[j-1]时,最长公共子序列的长度应该增加一,即dp[i][j]=dp[i-1][j-1]+1;

情况二:当text[i-1]!=text[j-1]时,最长公共子序列的长度应该为dp[i-1][j]或者dp[i][j-1]。


比如说有两个字符串bdc和bd,它们的最长公共子序列的长度应该是①bdc和b最长公共子序列长度1,②bd和bd的最长公共子序列的长度2。


两者之间取一个最大值即为dp[i][j]的值。


综上所述,动态规划方程为:

当text[i-1]=text[j-1]时,dp[i][j]=dp[i-1][j-1]+1;

当text[i-1]!=text[j-1]时,dp[i][j]=max(dp[i-1][j],dp[i][j-1])。


3、正确地初始化dp数组。


m为字符串1的长度,n为字符串2的长度,因此为dp数组开辟空间的时候一定要注意。


dp数组肯定设为二维数组。


因为dp[i][j]表示的是text1中0~i-1区间的字符串和text2中0~j-1区间的字符串的最长公共子序列,所以最后返回的是dp[m][n]。


当其中一个字符串取空串时,它和另外一个字符串的最长公共子序列长度一定为0。


也就是dp[0][j]=0,dp[i][0]=0。


因为初始化的时候数组默认为0,也就不用再另外赋值了。


dp[0][0]自然也为0,讨论下去也没什么意义。


4、确定遍历顺序。


因为dp[i][j]依赖于dp[i-1][j-1],dp[i-1][j],dp[i][j-1]。


遍历顺序也就相应的确定为从前往后遍历,并且从i=1和j=1的时候开始遍历。


5、举例推导dp数组,验证动态方程。


下面为代码段,Java语言实现。


 public int longestCommonSubsequence(String text1, String text2) {
            int m = text1.length();
            int n = text2.length();

            int [][]dp = new int[m+1][n+1];
            for(int i=1;i<=m;i++){
                for(int j=1;j<=n;j++){
                    if(text1.charAt(i-1)==text2.charAt(j-1)){
                        dp[i][j]=dp[i-1][j-1]+1;
                    }
                    else {
                        dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                    }
                }
            }

            return dp[m][n];
  
    }

如果有错误还请大家指出,我会虚心改正。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/567760.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存