概念
动态规划:先解决子问题,再逐步解决大问题。
动态规划和贪心算法:都是自底向上分析问题的算法,区别在于动态规划着眼于全局最优解,而贪心算法着眼于局部最优解。
动态规划和分治法:动态规划是自底向上分析问题,先解决小问题再解决大问题,而分治法是自顶向下分析问题,先拆分大问题为小问题,解决了小问题,大问题也就被解决了。
查找最长公共子串
题目描述 力扣 718 最长重复子数组
给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
题目解析
经典的背包问题
首先我们来画一个背包网格,单元格中的值代表了公共子串的长度,横纵坐标分别表示两个数组的各个元素
- 如果两个元素的值相同,那么就在前一步(也就是d p[i-1][j-1] )的基础上 +1(前一步代表有多少公共子串)
- 如果两个元素的值不相同,则为0(说明公共子串断开了)
- 最终结果为网格中最大的值,不一定是最后一个格中的值
伪代码实现
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
int n1 = A.size(), n2 = B.size();
vector<vector<int>> dp(n1+1, vector<int>(n2+1, 0));//初始化所有网格为0,图中只有5行5列,其实还隐藏了最上面和最左边的元素,因为都是0,不用计算,但必须要初始化
int res = 0;//记录网格中的最大值
for(int i=1; i<=n1; i++)//dp隐藏了第0行第0列
{
for(int j=1; j<=n2; j++)
{
if(A[i-1]==B[j-1])
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = 0;
res=max(ans,dp[i][j]);//更新最大值
}
}
return res;
}
};
查找最长公共子序列
先说明两种题目的不同之处
- 最长公共子串,子串在原字符串中必须两两相邻;
- 最长公共子序列,子序列在原字符串中不必两两相邻,只需按原顺序排列即可。
题目描述 1143 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
可以自己先画一个网格,思考一下各个单元格之间的关系。
题目解析
首先我们来画一个网格,单元格中的值代表了公共子序列的长度,横纵坐标分别表示两个字符串的各个字母
- 如果两个字母相同,那么就在前一步(也就是d p[i-1][j-1] )的基础上 +1(前一步代表有多少公共子串)
- 如果两个字母不相同,则为上面和左边位置中最大的那个值
伪代码实现
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m=text1.length(),n=text2.length();
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
int res=0;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
if(text1[i-1]==text2[j-1])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
res=max(res,dp[i][j]);
}
return res;
}
};
相似例题 永不相交的线
查找好的公共子序列
题目描述
输入一个字符串s 找出最长的子字符串满足1807的顺序,好的子序列就是指按照1807的顺序排列的子序列,1807可以重复。
例如
输入:1180011111877007
输出:11
其中好的最长子序列为11111118007
题目解析
同样先画一个网格,单元格中的值代表了好的公共子序列的长度,横纵坐标分别表示两个字符串的各个数字
- 如果两个数字不相同,则为上面和左边位置中最大的那个值
- 如果两个数字相同,那么就在上面和左边位置中最大值的基础上+1
代码实现
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int GetMaxLen(string str1,string str2)
{
int m=str1.length();
int n=str2.length();
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
int result=0;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
if(str1[i-1]==str2[j-1])
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
result=max(result,dp[i][j]);
}
return result;
}
int main()
{
string str1;
string str2="1807";
cin>>str1;
int len=GetMaxLen(str1,str2);
cout<<len<<endl;
system("pause");
return 0;
}