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

问题描述:

字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列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];
  
    }

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

你可能感兴趣的:(动态规划,算法)