动态规划将一个复杂问题分解为若干个子问题,通过综合子问题的最优解来获得原问题的最优解。
如果一个问题的最优解可以由其子问题的最优解有效地构造出来,那么称这个问题拥有最优子结构。一个问题必须拥有重叠子问题和最优子结构,才能用动态规划去解决。
最大连续子序列和
给定一个数字序列:a1,a2,...,an,求 i, j (1<=i<=j<=n),使得ai+...+aj最大,输出这个最大和。
思路:设置数组dp[i]表示以A[i]为末尾的连续序列的最大和。
//A[i]已知
dp[0] = A[0];
for(int i=1;i<n;i++){
dq[i] = max(A[i], A[i]+dp[i-1]);
}
int k=0;
for(int i=1;i<n;i++){
if(dp[i]>dp[k]) k = i;
}
最长不下降子序列(LIS)
在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是不下降(非递减)的。
思路:令dp[i]表示以A[i]结尾的最长不下降子序列长度。
//A[i]已知
int ans = -1;//存放最大dp[i]
for(int i=0;i<n;i++){
dp[i] = 1;
for(int j=0;j<i;j++){
if(A[i]>=A[j] && (dp[i]<dp[j]+1))
dp[i] = dp[j]+1;
}
ans = max(ans,dp[i]);
}
最长公共子序列(LCS)
给定两个字符串(或数字序列)A和B,求一个字符串,使得这个字符串是A和B的最长公共部分(子序列可以不连续)。
思路:令dp[i][j]表示字符串A的i号位和字符串B的j号位之前的LCS长度。
- 若A[i]==B[j],则dp[i][j] = dp[i-1][j-1] + 1;
- 若A[i] != B[j],则dp[i][j] = max{ dp[i][j-1], dp[i-1][j] }。
for(int i=0;i<=lenA;i++){
dp[i][0] = 0;}
for(int i=0;i<=lenB;i++){
dp[i][0] = 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];
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
最长回文字符串
给出一个字符串S,求S的最长回文子串的长度。
思路:令dp[i][j]表示S[i]至S[j]所表示的子串是否为回文子串,是为1,否为0。
for(int i=0;i<len;i++)
{ dp[i][i] = 1;
if(i<len-1){
if(S[i]==S[i+1]){
dp[i][i+1] = 1;
ans = 2;
}
}
}
for(int L=3;L<=len;L++)
{ for(int i=0;i+L<=len;i++){
int j = i+L-1;
if(S[i]==S[j] && dp[i+1][j-1]==1){
dp[i][j] = 1;
ans = L;
}
}
}