子串:在给定的字符串中选取连续的一段
子序列:可以不连续,但是要保证出现的顺序与原字符串相同
比如字符串ABCDEFG
ABC既是子串又是子序列
ACD只是子序列
一、最大连续子序列和
给定一个整数序列A1,A2……An。求最大的连续的子序列的和。
比如{1,-2,3,1,-1,2}的最大连续子序列的和为5(3+1-1+2)
万能枚举???每次枚举l和r,求区间[l,r]的和
时间复杂度O(n^3)。
1.定义状态:
dp[i]表示以Ai为结尾的连续子序列的最大和
2.状态转移:
if(dp[i-1]>0) dp[i]=dp[i-1]+a[i];
else dp[i]=a[i];
二、最长递增子序列(LIS)
给出长度为N的数组,找出这个数组的最长递增子序列的长度。
(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
1.定义状态:
dp[i]表示以Ai为结尾的最长递增子序列的长度。
i= 1时,{5} dp[1] = 1
i= 2时, {1} dp[2] = 1
i= 3时,{6},{5,6} {1,6} dp[3] = 2
i= 4时,{8},{6,8},{1,8},{5,8},{5,6,8},{1,6,8} dp[4]= 3
i= 5时 ………
2.状态转移:
dp[i]=max{dp[i],dp[j]+1} (j < i && a[j] < a[i])
ans = max{dp[i]}
for (int i = 1;i <= n;i++){
dp[i] = 1;
int j = i-1;
while (j > 0){
if (a[i] > a[j]){
dp[i] = max(dp[i],dp[j]+1);
}
j--;
}
ans = max(dp[i],ans);
}
ologn法:
1.定义状态:
d[k]表示长度为j的最长递增子序列最后一项的最小值。
性质:
1. d[k]在计算过程中单调不升;
2. d数组是有序的,d[1]<d[2]<..d[n]。
解法:
1. 设当前最长递增子序列为len,考虑元素a[i];
2. 若d[len]<a[i],则len++,并将d[len]=a[i];
否则,在d[0-len]中二分查找,找到第一个比它小的元素d[k],并d[k+1]=a[i].()
三、最长公共子序列(LCS)
给定两个序列求他们最长相同的子序列的长度。
例如:A={a,b,c,h,e,f} B={a,e,b,h,d,f}的最长公共子序列为{a,b,h,f},长度为4
1.定义子状态:
dp[i][j]表示A序列前i项和B序列前j项的最长公共子序列的长度
2.状态转移:
(1)a[i] = b[j]时,dp[i][j] = dp[i-1][j-1]+1
比如A[2]=B[3]= b,
LCS(1,2) = {a}
LCS(2,3) = {a,b}
(2)a[i] != b[j]时,dp[i][j] = max{dp[i-1][j], dp[i][j-1]}
假设LCS(i,j)的最后一位是t;
t != a[i]时,dp[i][j] = dp[i-1][j];
t != b[i]时,dp[i][j] = dp[i][j-1];
dp[i][j] = max{d[i-1][j], dp[i][j-1]}
for(int i = 0;i <= lena;i++) dp[i][0] = 0;
for(int i = 0;i <= lenb;i++) dp[0][i] = 0;
for(int i= 1;i <= lena;i++){
for (int j = 1;j <= lenb;j++){
if (a[i] == b[j]){
dpi][j] = dp[i-1][j-1] + 1;
}
else{
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}
}
}
四、最长公共子串
给定两个序列求他们最长公共子串的长度。
例如:A={a,b,d,b,c,g,h} B={e,a,b,e,d,b,c,g,a}的最长公共子序列为{ d,b,c,g},长度为4
1.定义子状态:
dp[i][j]表示以A序列第i项和B序列第j项为结尾的最长公共子串的长度
2.状态转移:
A[i] = B[i]时,dp[i][j] = dp[i-1][j-1] + 1;
A[i] != B[i]时,dp[i][j] = 0;
for(int i = 0;i <= lena;i++) dp[i][0] = 0;
for(int I = 0;i <= lenb;i++) dp[0][i] = 0;
for(int i= 1;i <= lena;i++){
for (int j = 1;j <= lenb;j++){
if (a[i] == b[j]){
dp[i][j] = dp[i-1][j-1] + 1;
}
else{
dp[i][j] = 0;
}
}
ans = max(ans,dp[i][j]);
}