最长的所有三种情况下,最长的常见子序列最多

  • 本文关键字:情况下 有三种 常见 algorithm
  • 更新时间 :
  • 英文 :


我接近最长的常见子序列,为:

LCS(m,n) = max( LCS(m-1,n), LCS(m,n-1), LCS(m-1,n-1) + (String1[m]==String2[n]) );

文本显示问题的逻辑:

if( String1[m]==String2[n] )
    LCS(m,n) = LCS(m-1,n-1) + 1;
else LCS(m,n) = max( LCS(m-1,n), LCS(m,n-1) );

我的方法会产生不正确的结果吗?如果是,那么在哪种情况下?如果正确,您如何证明正确性?

预先感谢!

我的(不良)java版本,它运行正确?

//'main' method must be in a class 'Rextester'.
//Compiler version 1.8.0_111
import java.util.*;
import java.lang.*;
class Rextester
{
    public static void main(String args[])
    {
        int[] a = {1,1,1,1,2,3,2,3};
        int[] b = {1,1,1,1,3,4,3,4};
        System.out.println(solve(a, b).toString());
        System.out.println(solve2(a, b).toString());
    }
    private static void printL(int[][]len, int m, int n, int[] a, int[] b)
    {
        System.out.print("  a→ ");
        for (int j = 0; j < m; ++j)
        {
            System.out.print(a[j]);
            System.out.print(" ");
        }
        System.out.println();
        for (int i = 0; i <= n; ++i)
        {
            if (i > 0) { System.out.print(" "); System.out.print(b[i-1]); System.out.print(" "); }
            else { System.out.print("b↓ "); }
            for (int j = 0; j <= m; ++j)
            {
                System.out.print(len[i][j]);
                System.out.print(" ");
            }
            System.out.println();
        }
    }
    private static List<Integer> solve(int[] a, int[] b)
    {
        int m = a.length;
        int n = b.length;
        System.out.println("Method 1");
        int[][] len = new int[n+1][m+1];
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < m; ++j)
                len[i+1][j+1] = a[j] == b[i] ? 1 + len[i][j] : Math.max(len[i+1][j], len[i][j+1]);
        printL(len, m, n, a, b);

        List<Integer> c = new ArrayList<Integer>();
        for (int i = n - 1, j = m - 1; len[i+1][j+1] > 0;)
        {
            if (a[j] == b[i]) { c.add(a[j]); i--; j--; }
            else if (len[i+1][j] < len[i][j+1]) i--;
            else j--;
        }
        Collections.reverse(c);
        return c;
    }
    private static List<Integer> solve2(int[] a, int[] b)
    {
        int m = a.length;
        int n = b.length;
        System.out.println("Method 2");
        int[][] len = new int[n+1][m+1];
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < m; ++j)
                len[i+1][j+1] = Math.max(Math.max(len[i+1][j], len[i][j+1]), (a[j] == b[i] ? 1 : 0) + len[i][j]);
        printL(len, m, n, a, b);
        List<Integer> c = new ArrayList<Integer>();
        for (int i = n - 1, j = m - 1; len[i+1][j+1] > 0;)
        {
            if (a[j] == b[i]) { c.add(a[j]); i--; j--; }
            else if (len[i+1][j] < len[i][j+1]) i--;
            else j--;
        }
        Collections.reverse(c);
        return c;
    }
}

在Rextester上输出:

Method 1
  a→ 1 1 1 1 2 3 2 3 
b↓ 0 0 0 0 0 0 0 0 0 
 1 0 1 1 1 1 1 1 1 1 
 1 0 1 2 2 2 2 2 2 2 
 1 0 1 2 3 3 3 3 3 3 
 1 0 1 2 3 4 4 4 4 4 
 3 0 1 2 3 4 4 5 5 5 
 4 0 1 2 3 4 4 5 5 5 
 3 0 1 2 3 4 4 5 5 6 
 4 0 1 2 3 4 4 5 5 6 
[1, 1, 1, 1, 3, 3]
Method 2
  a→ 1 1 1 1 2 3 2 3 
b↓ 0 0 0 0 0 0 0 0 0 
 1 0 1 1 1 1 1 1 1 1 
 1 0 1 2 2 2 2 2 2 2 
 1 0 1 2 3 3 3 3 3 3 
 1 0 1 2 3 4 4 4 4 4 
 3 0 1 2 3 4 4 5 5 5 
 4 0 1 2 3 4 4 5 5 5 
 3 0 1 2 3 4 4 5 5 6 
 4 0 1 2 3 4 4 5 5 6 
[1, 1, 1, 1, 3, 3]

我的粗略证明:

如果您查看上表中表中的任何行LCS(M),您会发现它们的值都在增加,或者它们都单调地增加。它们不能减小,因为LCS(m,n)表示长度为n的长度为m和sub(sub)字符串的最长常见子序列,如果n2> = n1,则LCS(m,n2)> = lcs(m,m,m,n1),因为如果N2> = N1,LCS(M,N2)包含LCS(M,N1)。

对于LCS(N)列,您使用相同的证明。现在,您有LCS(M,N)&LT; = LCS(M,N 1)和LCS(M,N)&LT; = LCS(M 1,N),这意味着您最大的三种可能情况是正确的。

LCS(m,n) = max( LCS(m-1,n), LCS(m,n-1), LCS(m-1,n-1) + (String1[m]==String2[n]) ); 仅在String1[m] != String2[n](LCS(m-1,n-1) > LCS(m,n-1)LCS(m-1,n-1) > LCS(m-1,n))时采用错误的路径,但是后一种情况(LCS(m-1,n-1) > LCS(m,n-1)LCS(m-1,n-1) > LCS(m-1,n))永远不会发生。因此您的方法是正确的。

最新更新