动态规划算法题总结

维护一个dp[i]表示包含i位置的最大连续子数组和,

for循环到i,dp[i]等于num[i]与dp[i-1]+num[i]的最大值

维护一个ret作为返回值 在每次更新dp[i]时实时更新

 

逆向思维 维护两个dp 命名为f和g

f[i]表示以i位置为结尾的所有子数组的最大和

g[i]表示以i位置为结尾的所有子数组的最小和

动态规划之后取f[i]和sum-g[i]的最大值即可

值得注意的是如果全部都是负数 会错误

因此加一个判断 全都是负数就取f[i]最大值

 

多状态问题需要两个dp

一个f[i]记录以i位置结尾的最大值

一个g[i]记录以i位置结尾的最小值

更新时

如果nums[i]>0

f[i]会取到f[i-1]*nums[i]或nums[i]

不然

f[i]会取到g[i-1]*nums[i]

g[i]同理

f[i]等于g[i-1]*nums[i]与f[i-1]*nums[i]与nums[i]的最大值

g[i]等于f[i-1]*nums[i]与g[i-1]*nums[i]与nums[i]的最小值

返回最大的f[i]即可

上一题的变种 要求我们求长度

维护f[i]为以i结尾的乘积为正数子数组最大长度

维护g[i]为以i结尾的乘积为负数子数组最大长度

遍历nums[i]

nums[i]大于0时

f[i]=f[i-1]+1

如果g[i-1]==0,说明还没遇到过负数,g[i]=0

否则g[i]=g[i-1]+1

nums[i]小于0时

如果g[i-1]==0,说明还没遇到过负数,f[i]=0

否则f[i]=g[i]+1

g[i]=f[i-1]+1

同样一个变量跟踪记录最大值

dp[i]为以i结尾的等差数列个数

如果i,i-1,i-2构成了等差数列

则dp[i]=dp[i-1]+1

ret+=dp[i]

解释 因为1 2 3 4构成等差数列

则后面加一个数也能和前面的子数组构成等差数列

然后还有和前两个数构成的一个

两个dp

f为以i结尾而且为下降趋势的子数组的长度

g为以i结尾而且为上升趋势的子数组的长度

遍历nums[i] nums[i]>nums[i-1]则f[i]=g[i-1]+1

反之则g[i]=f[i-1]+1

设计一个二维的dp[i][j]为以i j为结尾的最长等差数列的长度

先遍历i 再遍历j 因为这样我们可以一边填dp[i][j],一边将离倒数第二个数nums[i]最近的满足nums[i]-nums[j]=nums[k]-nums[i],的k值(即索引)记录在hash[nums[k]]中,这样的话只要是和倒数第二个数nums[i]有关的,无论倒数第一个数nums[j]是谁 都可以通过hash来找

填入hash的时机在遍历每个nums[i]后

同样构造一个变量跟踪记录最大值

dp[i]表示以i结尾的最长等差子序列的长度

正常做是固定最后一个元素 然后从前往后找

发现等差的就加上 发现最大的就记下来

正常做法会超时

优化做法维护一个hash[nums[i]]表示以nums[i]结尾的最长等差子序列的长度

因为我们是从前往后填hash 所以每次越往后的值都会覆盖掉前面的

越往后的值肯定是离dp[i]更近的

这题也是利用一个hash表 用哈希表找到需要的值的索引

可以先初始化 把所有的nums[i]的索引i填入hash[nums[i]]

也可以一边填表一边填hash

 

定义dp[i][j]为将以i开头j结尾的字串变为回文串的最少插入次数

从后往前遍历 以便得到值

若s[i]==s[j]

则dp[i][j]=dp[i+1][j-1]

因为i位置和j位置已经构成字符串 就看他内层的了

若不等于

则等于dp[i+1][j]和dp[i][j-1]比较小的 因为两边各自抵消另一个都可以看前面二者

找等差子序列的个数

dp[i][j]代表i开头j结尾的等差子序列的个数

正常也需要向前一个个找能和i位置j位置构成等差子序列的元素的dp值

优化做法是将所有的索引都放进去

而且要定义为long long 不然可能溢出

dp[i][j]表示s1的[0,i]区间及s2的[0,j]区间的所有子序列中,公共子序列的长度

根据两边最后一个位置的情况动态规划

若s1[i]==s2[j]

则dp[i][j]=dp[i-1][j-1]+1等于它们上一个位置的公共子序列+1

若不同则等于dp[i-1][j]和dp[i][j-1]的较大者

dp[i][j]表示:s字符串[0,j]区间内所有的子序列中,有多少个t字符串[0,i]区间的字符串

根据s的子序列最后一个位置包不包含s[j]来构建状态转移方程

如果当前的dp[i][j]肯定有dp[i][j-1]的值 因为新加了一个s[j]肯定更有匹配能力,前面到j-1为止的子序列有多少个能匹配到i,加一个肯定也能

然后根据s[j]等不等于t[i],如果等于,说明有dp[i-1][j-1]数量个子序列能匹配字符串(最后一个被解决了)

dp[i][j]表示p[0,j]的字符串能否匹配s[0,i]位置的字符串

状态转移方程的填表方式为

遇到s[i]和p[j]

如果相等 则依靠dp[i-1][j-1]

若p[j]=='?'

则为dp[i][j-1]

若p[j]=='*'

则为dp[i-1][j]||dp[i][j-1]

因为*可以匹配任意多个

则若p[j]能匹配到s[i-1]那肯定能匹配完

若j-1能匹配i j也能匹配空串

初始化时 所有连续的*都能匹配空串

则dp[0][j]=1 当*连续

本题和上一题不同的是 初始化时要看字符前面有没有* 要是有则dp[0][x]=dp[0][x-2]

遍历时注意三种状态

s[i-1]==p[j-1]时

则dp[i][j]=dp[i-1][j-1]

p[j-1]=='.'时

dp[i][j]=dp[i-1][j-1]

p[j-1]=='*'时 有三种情况

若dp[i][j-2]为真 则到j-2位置就能匹配上

不然就检查上一个位置

若p[j-2]=='.'就看dp[i-1][j-1]

若p[j-2]==s[i-1]也看dp[i-1][j-1]

dp[i][j]为s1的0到i的子串和s2的0到j的子串能不能拼凑出s3的0到i+j的字符串

状态转移时

遍历i与j

当s1[i]==s3[i+j-1]时

若dp[i-1][j]为真则dp[i][j]为真

当s2[j]==s3[i+j-1]时

若dp[i][j-1]为真则dp[i][j]为真

转换一下 改成求公共子序列acill码最大和 

dp[i][j]为分别到i j位置的公共子序列的acill码最大和

状态转移时 四种情况 

最大值有i 有j

那一定是因为s1[i]==s2[j] dp有dp[i-1][j-1]+s1[i]

最大值有i 无j

也许dp[i][j-1]的公共子序列acill码最大和更大

最大值无i 有j

也许dp[i-1][j]的公共子序列acill码最大和更大

01背包问题

dp[i][j]表示在前i个物品中挑选 总体积不超过j的最大值

遍历每个物品nums[i],考虑选择它与不选它中的最大值

dp[i][j]表示 从前i个数中选 所有的选法中 能否凑成j这个数

遍历每个i

dp[i][j]的值为不选i和选i且j-nums[i]>=0的正值

初始化应该将所有dp[i][0]置为1

因为任意个数可组成0

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值