最长公共子序列——动态规划

什么是最长公共子序列?

最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列。最长公共子序列问题是一个经典的计算机科学问题,也是数据比较程序,比如Diff工具,和生物信息学应用的基础。它也被广泛地应用在版本控制,比如Git用来调和文件之间的改变。
 
代码如下:
 1 package com.lzp.util;
 2 
 3 import java.util.Scanner;
 4 
 5 /**
 6  * @Author LZP
 7  * @Date 2021/3/25 19:34
 8  * @Version 1.0
 9  *
10  * 最大公共子序列
11  * 若有多个最大公共子序列,则将所有的情况都打印出来
12  */
13 public class LCS {
14     private static int num = 0;
15     public static void main(String[] args) {
16         Scanner input = new Scanner(System.in);
17         int N = input.nextInt();
18         int[] A = new int[N];
19         int[] B = new int[N];
20         int[][] dp = new int[N + 10][N + 10];
21         for (int i = 0; i < N; i++) {
22             A[i] = input.nextInt();
23         }
24         for (int i = 0; i < N; i++) {
25             B[i] = input.nextInt();
26         }
27 
28         // 找到最长公共子序列
29         // b数组用于回溯找到最长公共子序列,1代表↖ 2代表↑ 3代表←
30         int[][] b = new int[N + 10][N + 10];
31         // 时间复杂度O(N^2)
32         for (int i = 1; i <= N; i++) {
33             for (int j = 1; j <= N; j++) {
34                 if (A[i - 1] == B[j - 1]) {
35                     dp[i][j] = dp[i - 1][j - 1] + 1;
36                     // 来源于前一行前一列
37                     b[i][j] = 1;
38                 } else if (dp[i - 1][j] > dp[i][j - 1]){
39                     // 查看前面是A数列少一位之后更长,还是B数列少一位之后更长,选较长的那个作为此时的长度
40                     dp[i][j] = dp[i - 1][j];
41                     // 来源于前一行
42                     b[i][j] = 2;
43                 } else {
44                     dp[i][j] = dp[i][j - 1];
45                     // 来源于前一列
46                     b[i][j] = 3;
47                 }
48             }
49         }
50 
51         int[] lcs = new int[N];
52         LCS(N, N, b, lcs, A);
53 
54         for (int i = 0; i < dp[N][N]; i++) {
55             System.out.printf("%d ", lcs[i]);
56         }
57     }
58 
59     /**
60      * 利用递归求出最长公共子序列
61      * 时间复杂度O(n)
62      */
63     public static void LCS(int i, int j, int[][] b, int[] lcs, int[] A) {
64         // 出口
65         if (i == 0 || j == 0) {
66             return;
67         }
68 
69         if (b[i][j] == 1) {
70             LCS(i - 1, j - 1, b, lcs, A);
71             lcs[num++] = A[i - 1];
72         } else if (b[i][j] == 2) {
73             LCS(i - 1, j, b, lcs, A);
74         } else {
75             LCS(i, j - 1, b, lcs, A);
76         }
77     }
78 }

运行结果:

 

posted @ 2021-03-25 21:59  没有你哪有我  阅读(161)  评论(0编辑  收藏  举报