动态规划求最长公共子序列问题

#include<iostream>
#include<string>
#include<vector>
using namespace std;

//找两个子串str1,str2的最长公共子串substr
void findLongestSubString(string &str1, string &str2, string &substr){
	if (str1.empty() || str2.empty()){
		return;
	}
	//定义二维数组lengt[str.size() + 1][str2.size() + 1]来保存最长公共子串的长度
	vector<vector<int> > length(str1.size() + 1, vector<int> (str2.size() + 1, 0) );
	//定义搜索状态二维数组state[str.size() + 1][str2.size() + 1],为了后面寻找最长公共子串元素
	vector<vector<int> > state(str1.size() + 1, vector<int> (str2.size() + 1, 0) );

	//下面就是运用动态规划求最长公共子串
	for(size_t i = 1; i <= str1.size(); i++){
		for(size_t j = 1; j <= str2.size(); j++){
			if(str1[i - 1] == str2[j - 1]){
				length[i][j] = 1 + length[i -1][j - 1];
				state[i][j] = 1;
			}
			else{
				length[i][j] = (length[i-1][j] >= length[i][j-1] ? length[i-1][j] : length[i][j-1]);
				if (length[i-1][j] >= length[i][j-1]){
					state[i][j] = 2;
				}
				else{
					state[i][j] = 3;
				}
			}
		}
	}
	for (size_t i = str1.size(), j = str2.size(); i > 0 && j > 0;){
		if (state[i][j] == 1){
			substr.push_back(str1[i-1]);
			i--;
			j--;
		}
		else if (state[i][j] == 2){
			i--;
		}
		else {
			j--;
		}
	}
	return;
}

//翻转字符串
void reverseString(string &str){
	if (str.empty()){
		return;
	}
	for (size_t i = 0, j = str.size() - 1; i < j; i++, j--){
		str[i] = str[i] ^ str[j];
		str[j] = str[j] ^ str[i];
		str[i] = str[j] ^ str[i];
	}
	return;
}

int main(void){
	string str1, str2, substr;
	//输入字符串str1,str2
	cin >> str1 >> str2;
	findLongestSubString(str1, str2, substr);
	reverseString(substr);
	cout << "string 1: " << str1 << endl << "string 2: " << str2 << endl << "substring: " << substr << endl;
	return 0;
}

给定字符串X=(X1,X2,...,Xm),Y= (Y1,Y2,...,Yn)。求字符串X和Y的最长公共子序列。

首先分析字符串X和Y的最后一个字符Xm和Yn:

1、如果Xm == Yn,那么Xm一定是字符串X和Y的最长公共子串中的最后一个元素。接下来只要分别求X的前m-1个元素组成的子串(X1,X2,...,Xm-1)和Y的前n-1个元素组成的子串(Y1,Y2,...,Yn-1)的最长公共子串。

2、如果Xm != Yn,那么X和Y的最长公共子串要么是(X1,X2,...,Xm)与(Y1,Y2,...,Yn-1)的最长公共子串;要么是(X1,X2,...,Xm-1)与(Y1,Y2,...,Yn)的最长公共子串。两者中选长度较长的。

下面列递推方程:

设length[ i ][ j ]表示字符串X的前i个字符与字符串Y的前j个字符的最长公共子串的长度。那么有上面的分析我们有:

length[0][0] = length[0][j] = length[i][0] = 0;   (1 <= i <= m, 1 <= j <= n)

if (Xi == Yj)           length[ i ][ j ] = length [i - 1][j - 1] + 1;           (i >= 1, j>=1)

if (Xi != Yj)
      length[ i ][ j ] = max(length[ i - 1][ j ], lenght[ i ][j - 1]);                    (i >= 1, j >= 1)

同时为了得到序列X和Y的最长公共子序列,设二维表state[m+1][n+1],其中state[i][j]表示在计算length[i][j]的过程中的搜索状态:

if(Xi == Yj)        state[i][j] = 1         //说明X的前i个元素和Y的前j个元素的最长公共子序列包含Xi,也就是X和Y的最长公共子序列包含Xi

if(Xi != Yj && length[i - 1][j] >= length[i][j - 1])
state[i][j] = 2;           //说明X的前i个元素和Y的前j个元素的最长公共子序列是由X的前i-1个元素和Y的前j个元素的最长公共子序列得到的。同时说明他们的最长公共子序列中不包含元素Xi。

if(Xi != Yj && length[i - 1][j] < length[i][j - 1]) 
state[i][j ] = 3; //说明X的前i个元素和Y的前j个元素的最长公共子序列是由X的前i个元素和Y的前j-1个元素的最长公共子序列得到的。同时说明他们的最长公共子序列中不包含元素Yj。

那么在用状态表搜索最长公共子序列时,如果state[i][j] == 1,表明Xi = Yj,元素Xi为最长公共子序列的元素,将这个元素存入子串中。下一个搜索方向为state[i - 1][ j - 1]。

如果state[i][j] == 2,表明Xi != Yj,length[i - 1][j] >= length[i][j - 1],并且最长公共子序列的元素在X的前i-1和Y的前j个元素的最长公共子序列中,那么继续搜素state[i-1][j]。

同理如果state[i][j] == 3,表明Xi != Yj,length[i - 1][j] < length[i][j - 1],那么继续搜素state[i][j - 1]。

时间: 2024-10-20 22:35:23

动态规划求最长公共子序列问题的相关文章

HDU 1243 反恐训练营 (动态规划求最长公共子序列)

反恐训练营 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3040    Accepted Submission(s): 693 Problem Description 当今国际反恐形势很严峻,特别是美国"9.11事件"以后,国际恐怖势力更是有恃无恐,制造了多起骇人听闻的恐怖事件.基于此,各国都十分担心恐怖势力会对本国社会造

九度OJ 1042 Coincidence (动态规划求最长公共子序列)

题目1042:Coincidence 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1689 解决:898 题目描述: Find a longest common subsequence of two strings. 输入: First and second line of each input case contain two strings of lowercase character a-z. There are no spaces before, inside or aft

hdoj-1159-Common Subsequence【动态规划求最长公共子序列】

Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 28152 Accepted Submission(s): 12556 Problem Description A subsequence of a given sequence is the given sequence with some element

动态规划解决最长公共子序列问题(转)

原文链接 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 解决思想: 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后

动态规划解最长公共子序列问题(转)

 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列

(hdu step 3.2.2)Common Subsequence(简单dp:求最长公共子序列的长度)

在写题解之前给自己打一下广告哈~..抱歉了,希望大家多多支持我在CSDN的视频课程,地址如下: http://edu.csdn.net/course/detail/209 题目: Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 976 Accepted Submission(s): 538   Probl

算法导论_动态规划_最长公共子序列

一.动态规划的概念 动态规划(Dynamic Programming)是通过组合子问题的解而解决整个问题的.分治是指将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原始问题的解,与此不同,动态规划适用于子问题不是独立的情况,也就是各个子问题包含公共的子问题.在这种情况下,采用分治法会做许多不必要的工作,即重复地求解公共地子问题.动态规划算法对每个子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案. 动态规划通常应用于最优化问题.此类问题可

[algorithm]求最长公共子序列问题

最直白方法:时间复杂度是O(n3), 空间复杂度是常数 reference:http://blog.csdn.net/monkeyandy/article/details/7957263 /** ** [email protected] ** http://blog.csdn.net/MonkeyAndy **/ 首先介绍动态规划方法的相关知识 动态规划方法的基本思想: 分成若干个子问题,先求解子问题,然后根据子问题的解求得原问题的解.经分解得到的子问题往往不是互相独立的.可重复利用! 其核心思

【算法导论之七】动态规划求解最长公共子序列

一.动态规划的概念 动态规划(Dynamic Programming)是通过组合子问题的解而解决整个问题的.分治算法是指将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原始问题的解,与此不同,动态规划适用于子问题不是独立的情况,也就是各个子问题包含公共的子问题.在这种情况下,采用分治法会做许多不必要的工作,即重复地求解公共地子问题.动态规划算法对每个子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案. 动态规划通常应用于最优化问题.此类问