子串和子序列的区别在于子串是连续的而子序列是不连续的 学习了很久的动态规划问题 做了很多的题目我发现动态规划的突破口在于找到递推关系式也就成功的找到了转移方程 下面我们进入最长子串问题 先定义一个二维数组dp[][] dp[i][j]表示str[i-1]==str[j-1]那么如果str[i-1]==str[j-1]那么dp[i][j]==dp[i-1][j-1]+1如果当前两个相等那么直接就等于上一个的连续长度+1 如果不相等那么dp[i][j]=0;
if(str1[i]==str2[j])dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=0;
ok 这个就是我们需要找到转移方程 那么最长的长度在哪里我们不确定所以需要比较找出 这就是全部的思路了下面给出完整代码
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int dp[1000][1000];
string str1,str2;
void slove()
{
for(int i=0;i<=str1.length();i++)
{
dp[i][0]=0;
}
for(int i=0;i<=str2.length();i++)
{
dp[0][i]=0;
}//初始化我们记录下标从1开始所以dp[0][i]和dp[j][0]都是0
int maxed=0,x,y;
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]=0;
if(maxed<dp[i][j])maxed=dp[i][j];
}
}
cout<<maxed<<endl;
}
int main()
{
cin>>str1>>str2;
cout<<str2<<endl;
slove();
}
那么连续的序列和思路和上面的相似定义一个一维数组dp[] dp[i]表示截至到i-1最大和(注意起点我们是不知道)如果dp[i-1]+arr[i]>arr[i]那么dp[i-1]=arr[i]否则dp[i]=dp[i-1]+arr[i]同样因为我们是吧一个序列分成了好多个子序列所以我们不知道哪一个子序列最大所以我们需要遍历比较具体代码如下
#include<iostream>
#include<cstring>
using namespace std;
int arr[100001],n,Maxsum[100001];
int slove()
{
memset(Maxsum,0,sizeof(Maxsum));
int ans=0;
for(int i=1;i<=n;i++)
{
dp[i]=max(dp[i-1]+arr[i],arr[i]);
if(ans<dp[i])ans=dp[i];
}
return ans;
}
最长回文子串 那么我们还是老样子找到转移方程 定义一个二维数组booldp[][]dp[j][i]以j为起点i为终点的子串 判断这个子串是不是回文字符串 我们先判断str[i]==str[j]是否为真 若为真则取决于dp[i-1][j+1]是否为真若也为真则就是回文子串 否则不是 str[i]!=str[j]那么直接就不是回文字符串了
#include<bits/stdc++.h>
using namespace std;
bool dp[1000][1000];
string str;
int slove()
{
memset(dp,false,sizeof(dp));
int ans=0;
for(int i=0;i<str.length();i++)
{
for(int j=0;j<=i;j++)
{
if(i-j<2)dp[j][i]=(str[i]==str[j]);// 如果子串只有一个或者两个字符那么它里面根本没有其他子串只用判断最外面两个是不是就可以了
else dp[j][i]=((str[i]==str[j])&&dp[j+1][i-1]);
if(dp[j][i]&&(i-j+1)>ans)ans=i-j+1;//i-j+1表示长度
}
}
return ans;
}