系列文章目录
【动态规划】最长子串问题汇总(四)最长公共上升子序列
【动态规划】最长子串问题汇总(六)归纳对比
目录
前言
在练习算法的过程中,发现各种子序列问题容易混淆,问题通常是连续,公共,上升(递增)三词随意组合,本系列就最长子串(子序列)问题进行归纳对比
一、题目描述
给定两个字符串(仅包含小写字母),求其最长公共上升子序列长度
二、输入输出样例
输入是两个仅包含小写字母的字符串(数组同理),输出是一个正整数,表示最长公共上升子序列的长度
输入:s1 = "abcdeb", s2="aceb"
输出:3
此样例中,最长公共子序列是 "aceb",但最长公共上升子序列是 "ace"
三、算法分析
定义一个二维 dp 数组,dp[i][j] 表示第一个字符串前 i 个字符、第二个字符串前 j 个字符、且以s2[ j ]结尾的子序列长度
状态分为两种( i:1~n )
①最长公共上升子序列不包含 s1[i-1],所以用 dp[i-1][ j] 来更新 dp[i][ j]
②最长公共上升子序列包含 s1[i-1](即s1中第 i 个字符),这种状态划分分析起来比较困难
因为已经包含了s1[i-1],此时有s1[i-1]==s2[j-1],则看最长公共上升子序列的倒数第2个数
如果:Ⅰ 最长公共上升子序列只包含s1[i-1],倒数第2个数为空,长度为 1
Ⅱ 最长公共上升子序列的倒数第2个数是s2[0]的集合,最大长度是dp[i-1][1]+1
Ⅲ 最长公共上升子序列的倒数第2个数是s2[0~1]的集合,最大长度是dp[i-1][2]+1
Ⅳ ......
最长公共上升子序列的倒数第2个数是s2[0~ j-2 ]的集合,最大长度是dp[i-1][ j-1]+1
所以 for(int k=1;k<j;k++){ // k: 1~ j - 1
if(s1[i-1]>s2[k-1]) // s1[i-1]和s2[k-1]分别为最长公共上升子序列的倒数第1、第2个
max_len=max(max_len,dp[i-1][k]+1);
}
ps:有人可能不理解为什么把s2[k-1]看作为最长公共上升子序列的倒数第2个,由于我们定义dp[i][j]表示第一个字符串前 i 个字符、第二个字符串前 j 个字符、且以s2[ j ]结尾的子序列长度,所以在dp[i-1][ k]中,s2[k-1]为s1[0~i-2]和s2[0~k-1]的最长公共上升子序列的倒数第1个
例如:dp[3][2]的状态表示为"abc"和"ac",最长公共上升子序列为"ac",为状态②,dp[3][2]=2
dp[4][2]的状态表示为"abcd"和"ac",最长公共上升子序列为"ac",不包含s1[3](即'd'),
为状态①,dp[4][2]=dp[3][2]
int getLength(string s1,string s2){
int m=s1.size(),n=s2.size(); //取字符串长度
vector<vector<int>> dp(m+1,vector<int>(n+1,0)); //开辟dp[m+1][n+1]
for(int i=1;i<=m;i++){ //遍历 s1
for(int j=1;j<=n;j++){ //遍历 s2
/*------------------区别部分------------------*/
if(s1[i-1]!=s2[j-1]){
dp[i][j]=dp[i-1][j];//子序列不包含s1[i-1],用dp[i-1][j]来更新dp[i][j]
}
else{ //s1[i-1]==s2[j-1] 当前(i,j)位置字符相同
int max_len=1;
for(int k=1;k<j;k++){ //遍历 s2[0~j-2],即第 1 到第 j-1个字符
if(s1[i-1]>s2[k-1]) //符合上升条件
max_len=max(max_len,dp[i-1][k]+1);
}
dp[i][j]=max(max_len,dp[i][j]);
}
/*------------------区别部分------------------*/
}
}
int ans=0;
for(int i=0;i<=n;i++) res=max(res,dp[m][i]);
//例"abcdeb"、"aceb",dp[6][0]=0,dp[6][1]=1,dp[6][2]=2,dp[6][3]=3
//dp[6][4]=2(dp[6][4]=dp[5][4]=dp[3][4]==dp[2][4]=2)
return ans; // 3
}
dp[6][4] 可以自行对着程序分析一下
/*------------------区别部分------------------*/
其中的代码是各种最长子串(子序列)问题的具体区别
/*------------------区别部分------------------*/