动态规划算法之最长公共子序列问题

来源:互联网 发布:c语言整数四则运算程序 编辑:程序博客网 时间:2024/06/05 20:35

问题描述
  给定两个字符串,寻找这两个字串之间的最长公共子序列。
输入格式
  输入两行,分别包含一个字符串,仅含有小写字母。
输出格式
  最长公共子序列的长度。
样例输入
abcdgh
aedfhb
样例输出
3
样例说明
  最长公共子序列为a,d,h。
数据规模和约定
  字串长度1~1000。
分析:求最长公共子序列,用动态规划~只需建立一个长宽为两个字符串长度+1的二维数组~dp[i][j]表示String a的前i个字符构成的字符串和String b的前j个字符构成的字符串这两者得到的最长公共子序列的长度为dp[i][j]~~~所以第0行和第0列所有的数都为0~

根据递推公式:

最后一个格子的长度就是两个字符串的最长公共子序列的长度~

#include <iostream>  using namespace std;  int dp[1001][1001];  int main() {      string a, b;      cin >> a >> b;      for(int i = 1; i <= a.length(); i++) {          for(int j = 1; j <= b.length(); j++) {              if(a[i-1] == b[j-1])                  dp[i][j] = dp[i-1][j-1] + 1;              else                  dp[i][j] = max(dp[i-1][j], dp[i][j-1]);          }      }      cout << dp[a.length()][b.length()];      return 0;  }  

这个解法只能解决求最长子序列长度的问题,并不能得到最长子序列。因此,可以改良一下:

一、问题描述

求两个字符序列的公共最长子序列。例如字符序列abcbdb和字符序列acbbabdbb的最长公共子序列为acbdb。

二、问题分析

(1)用L[i][j]表示子序列xi和yj的最长公共子序列的长度,动态规划函数为

L[i][j] = L[i - 1][j - 1] + 1,   xi等于yj

         = max(L[i][j - 1], L[i - 1][j]),     xi不等于yj

边界条件第0行和第0列均为0,即L[i][0] = L[0][j] = 0

上例中L填写情况如下



(2)因为不只要求出最大长度,还要寻找到公共最长子序列,所以在填表L[i][j]过程中,再填一个表S[i][j],

xi等于yj,设置S[i][j] = 1;

xi不等于yj,并且len[i + 1][j] >= len[i][j + 1],设置S[i][j] = 2;

xi不等于yj,并且len[i + 1][j] < len[i][j + 1],设置S[i][j] = 3;

填表S[i][j]完成后,具体如何找到最长公共子序列详见代码注释。

上例中S填写情况及寻找最长公共子序列过程如下


三、算法代码

public static void maxCommonChar(char [] a, char [] b){          int m = a.length;          int n = b.length;          int [][] len = new int[m + 1][n + 1];//保存动态规划过程中的公共子串长度          int [][] flags = new int[m + 1][n + 1];//保存动态规划过程中的标志位          for(int i = 0; i <= m - 1; i++){//实现动态规划函数              for(int j = 0; j <= n - 1; j++){                  if(a[i] == b[j]){//规划函数len[i + 1][j + 1] = len[i][j] + 1, a[i] == b[j]                      len[i + 1][j + 1] = len[i][j] + 1;                      flags[i + 1][j + 1] = 1; //设置标志位                  }else if(len[i + 1][j] >= len[i][j + 1]){                      len[i + 1][j + 1] = len[i + 1][j];                      flags[i + 1][j + 1] = 2;                  }else{                      len[i + 1][j + 1] = len[i][j + 1];                      flags[i + 1][j + 1] = 3;                  }              }          }          int k = len[m][n]; //最长公共子串长度          char [] commonChars = new char[k];//保存最长公共子串          int i = m, j = n;  //从右下角的格子出发        for(;i > 0 && j > 0;){              if(flags[i][j] == 1){//只有标志位为1相应位置上的字符才为公共字符                  commonChars[k - 1] = a[i - 1];                  k--;                  i--;                  j--;  //往斜上方的格子移动            }else if(flags[i][j] == 2){                  j--;  //往左边的格子移动            }else{                  i--;  //往上面的格子移动            }          }          System.out.println("最长公共子序列长度为:" + len[m][n]);          System.out.print("最长公共子序列为:");          for(int l = 0; l <= len[m][n] - 1; l++){              System.out.print(commonChars[l] + " ");          }  }  


阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孤独的名言 孤独与寂寞 孤独终老 孤独的歌 孤独的单词 孤独单词 孤独的猫 孤独和烈酒 孤独感测试 孤独 英语 孤独是什么 注定孤独 孤独星球 孤独的女人 孤独的表现 忍受孤独 喜欢孤独 孤独老人 孤独外向症 内心的孤独 孤独的孩子 孤独的英文 孤独症表现 内心孤独 孤独综合症 孤独的旅行 孤独的时候 寂寞孤独 孤独的夜晚 人生而孤独 孤独一生 孤独的夜 孤独人生 孤独世界 当众孤独 孤独成瘾 孤独性障碍 孤独的人群 孤独和寂寞 孤独抑郁 一生孤独