zoukankan      html  css  js  c++  java
  • 动态规划-最长公共子序列

    最长公共子序列

    最长公共子序列(Longest Common SubSequence)的问题描述为:

    给定两个字符串A和B,求一个字符串,使得这个字符串是 A 和 B 的最长公共部分

    例如:"sadstory" 和 "adminsorry" 的最长公共子序列为 "adsory",长度为 6

    如果是暴力解法遍历的话……设A和B的长度分别是 n 和 m,对于两个字符串的子序列各有 2n, 2m,然后再比较是否相同又需要 O(max(m,n)) ,这样总复杂度就会达到O(2m+n x max(m, n))。

    还是让我们来看看动态规划的做法。

    我们使用一个数组 dp[i][j] ,表示字符串 A 的 i 号位和字符串 B 的 j 号位之前的 LCS 长度(下标从 1 开始),如 dp[4][5] 代表 "sads" 和 "admin" 的LCS长度,那么可以根据 A[i] 和 B[j] 的情况,分为两种情况:

    • 如果 A[i] == B[j],那么字符串 A 和 B 的 LCS 增加了一位,即有 dp[i][j] = dp[i-1][j-1]+1
    • 如果 A[i] != B[j],那么字符串 A 的 i 号位和 B 的 j 号位之前的 LCS 无法延长,因此 dp[i][j] 会继承 dp[i-1][j]和dp[i][j-1] 中较大值,即 dp[i][j] = max(dp[i-1][j],dp[i][j-1])

    由此可以得到状态转移方程:

    if(A[i] == B[j]) dp[i][j] = dp[i-1][j-1]

    if(A[i] != B[j]) dp[i][j] = max(dp[i-1][j], dp[i][j-1])

    其中,如果某一个字符串的长度为 0,那么 LCS 一定为 0,所以有边界:

    dp[i][0] = dp[0][j] = 0

    这样状态 dp[i][j],只与其之前的状态有关,由边界出发就可以得到整个 dp 数组,最终 dp[n][m] 就是需要的答案,时间复杂度为 O(mn)。

    代码实现如下:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 100;
    char A[N], B[N];	// 存放字符串
    int dp[N][N];			
    
    int main() {
      int n;
      gets(A + 1);
      gets(B + 1);
      int lenA = strlen(A + 1);
      int lenB = strlen(B + 1);
      // 初始化边界
      for(int i = 0; i <= lenA; i++) {
        dp[i][0] = 0;
      }
      for(int i = 0; i <= lenB; i++) {
        dp[0][j] = 0;
      }
      // 状态转移方程
      for(int i = 1; i <= lenA; i++) {
        for(int j = 1; j <= lenB; j++) {
          if(A[i] == B[j]) {
            dp[i][j] = dp[i-1][j-1] + 1;
          }else {
            dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
          }
        }
      }
      // dp[lenA][lenB]就是答案
      printf("%d
    ", dp[lenA][lenB]);
      return 0;
    }
    
    /*
    
      input:
      sadstory
      adminsorry
    
      output:
      6
      
    */
    
  • 相关阅读:
    Codeforces Round #226 (Div. 2)
    内存管理
    C/C++ 函数
    Codeforces Round #225 (Div. 2)
    常用链表操作总结
    Codeforces Round #224 (Div. 2)
    Codeforces Round #223 (Div. 2)
    Codeforces Round #222 (Div. 2)
    -树-专题
    Codeforces Round #221 (Div. 2)
  • 原文地址:https://www.cnblogs.com/veeupup/p/12548256.html
Copyright © 2011-2022 走看看