动态规划经典问题

子串:在给定的字符串中选取连续的一段
子序列:可以不连续,但是要保证出现的顺序与原字符串相同
比如字符串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]);
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值