动态规划(DP)---- 最长公共子序列

由于期末考试的缘故耽搁了很长时间没有继续发表,在这里给大家道个歉哈。

上期内容给大家提到了硬币的三个类型的讲解,这期咱们来讲解DP的类型题最长公共子序列。

问题:给定两个序列X和Y,请你找出X和Y的最长公共子序列的长度。

这道题咱们可以利用暴力法利用循环枚举出所有的X子序列然后遍历Y的子序列来找到最长公共子序列,时间复杂度为O(n * 2 ^ m)。但是如果要是通过动态规划来分析这道题,那么时间复杂度为O(nm),下面进行分析利用动态规划如何解题?

首先咱们定义dp数组的含义,这里所求的为最长公共子序列的长度,那么咱们不妨给dp数组定义为最长公共子序列,那么分析维数,这里所要的是两个子序列,假设这两个子序列的长度分别为m和n,所以dp[m][n]代表含义为m长度的X序列和n长度的Y序列之间的最长公共子序列的长度。

定义完dp数组的含义,我们就要找到其状态方程,首先分析dp数组的含义,我们分析题干,这里通过递推dp数组来推出值,也就是对dp[i][j]分析可分为i = j与i ≠ j这两种情况。

当i = j时,代表两个子串的第i个和第j个是一样的,所以状态方程为

dp[i][j] = dp[i - 1][j - 1] + 1;

当i ≠ j时,代表两个子串的第i个和第j个是不一样的,所以咱们这里要找出最大的那一个作为当前遍历的值所对应的最长公共子序列,所以其状态方程为

dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);

这里为方便写代码,所以博主这里用C++语言写一下.....

#include 
#include    //cin >> 和 cout <<
#include    //memset初始化dp数组   
using namespace std;
const int N = 1000;
string str1,str2;
int dp[N][N];
int solve()
{
	memset(dp,0,sizeof(dp));//将dp数组初始化成0
	for(int i = 1;i <= str1.length();i++)
	{
		for(int j = 1;j <= str2.length();j++)
		{
			if(str1[i - 1] == str2[j - 1])//对应元素相等
			{
				dp[i][j] = dp[i - 1][j - 1] + 1;
			}
			else
			{
				dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);
			}
		}
	}
	return dp[str1.length()][str2.length()];
}
int main()
{
	while(cin >> str1 >> str2)
	{
		cout << solve() << endl;
	}
	return 0;
}

定义一个solve函数来计算最长公共子序列,这里的初始化是利用memset来将dp数组初始化为0,遍历顺序切记要从1开始遍历,最后return返回当前dp数组的值就是两个子串的最长公共子序列。

好了,今天的dp分享就到这里了,感谢收看,别忘记三连啊。

你可能感兴趣的:(动态规划,算法)