DP-03动态规划算法题目解析
Posted yifanrensheng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP-03动态规划算法题目解析相关的知识,希望对你有一定的参考价值。
目录
- 面试题14- I. 剪绳子/343. 整数拆分
- 面试题42. 连续子数组的最大和/53. 最大子序和
- 面试题47. 礼物的最大价值
一、面试题14- I. 剪绳子/343. 整数拆分
1.1 问题:
给定一个正整数?n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例?2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 ×?3 ×?4 = 36。
1.2 求解:
1)步骤一:定义子问题
假设n的最大值为f(n),可以将n拆分成i和n-i,问题变成 i乘以f(n-i),这样就变成了f(k),k<n的子问题了。
2)写出子问题的递推关系
和第一步一样,使用dp表示其值,但是要注意 i * (n - i) 本省也可能成为最大值;另外因为是遍历循环,要考虑计算过的dp[i],因此得到如下表达式:
dp[i] = max(dp[i], max(i * dp(n - i),i * (n - i)))
初始值:每个dp都设置为1
3)确定 DP 数组的计算顺序
而这里的 n 是什么呢?我们说了dp是自底向下的思考方式。因此这里的 n 实际上是 1,2,3,4... n。
自然地,我们用一层循环来生成上面一系列的 n 值。接着我们还要生成一系列的 i 值,注意到 n - i 是要大于 0 的,因此 i 只需要循环到 n - 1 即可。
4 )空间优化(可选)
因为要循环使用,所以无法进行空间优化
1.3 代码
class?Solution:
????def?integerBreak(self,?n:?int)?->?int:
????????dp=[1]*(n+1)
????????for?i?in?range(3,n+1):
????????????for?j?in?range(1,i):
????????????????dp[i]?=?max(j*dp[i-j],j*(i-j),dp[i])
????????return?dp[-1]
二、面试题42. 连续子数组的最大和/53. 最大子序和
2.1 问题:
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释:?连续子数组?[4,-1,2,1] 的和最大,为?6。
2.2 求解:
问题比较简单,一维数组的问题。
1)步骤一:定义子问题
假设n的最大值为f(n),可以将n拆分成i和n-i,问题变成 i加上f(n-i)或直接是f(n-i),这样就变成了f(k),k<n的子问题了
2)写出子问题的递推关系
上面的进行简化:
初始状态:将每个复制为0或数组的第一个值。
3)确定 DP 数组的计算顺序
很明显,使用自底向上的方式进行。具体代码见2.3的代码一
4 )空间优化(可选)
从代码也很明显看到,只用了dp[i-1]这个前置项,另外是最后输出的max(dp)也需要保留,其它是暂存也没有用到,所以可将其优化,将dp[i-1]用max_temp,最后的输出使用res。具体可见代码二。
2.3 代码
代码一:
class?Solution:
????def?maxSubArray(self,?nums:?List[int])?->?int:
????????n?=?len(nums)
????????if?n?==?0:return?0
????????else:
????????????dp?=?[nums[0]]?*(n)
????????????for?i?in?range(1,n): #注意这里不是n+1
????????????????dp[i]?=?max?(dp[i-1]+nums[i],nums[i])
????????????return?max(dp)
代码二:
class?Solution:
????def?maxSubArray(self,?nums:?List[int])?->?int:
????????n?=?len(nums)
????????if?n?==?0:return?0
????????else:
????????????max_temp?=?nums[0]
????????????res?=?max_temp
????????????for?i?in?range(1,n):
????????????????max_temp?=?max?(max_temp?+?nums[i],nums[i])
????????????????res?=?max(res,max_temp)
????????????return?res
三、面试题47. 礼物的最大价值
3.1 问题:
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
? [1,3,1],
? [1,5,1],
? [4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
3.2 求解:
是二维数组题,难度为中等偏上,和这题【1143. 最长公共子序列】类似
1)步骤一:定义子问题
题目说明:从棋盘的左上角开始拿格子里的礼物,并每次 向右 或者 向下 移动一格、直到到达棋盘的右下角。
根据题目说明,易得某单元格只可能从上边单元格或左边单元格到达。
很明显,缩小规模的子问题和原文题是等效的。
2)写出子问题的递推关系
定义二维矩阵,设动态规划矩阵?dp ,dp(i,j) 代表从棋盘的左上角开始,到达单元格?(i,j) 时能拿到礼物的最大累计价值。
3)确定 DP 数组的计算顺序
先行后列,从上到下进行计算即可。具体代码见3.3代码一。
4 )空间优化(可选)
对角进行替换,换成下图所示的例子,进一步优化空间:
?? | temp |
dp[j-1] | dp[j-1] |
只是用上面和左边的,所以可以重复利用,循环推进就可以了。具体见代码二。
3.3 代码
代码一:
class?Solution:
????def?maxValue(self,?grid:?List[List[int]])?->?int:
????????m?=?len(grid)
????????n?=?len(grid[0])
????????dp?=?[[0]*(n+1)?for?_?in?range(m+1)]???#(m+1)(n+1)的矩阵
????????for?i?in?range?(1,m+1):???#注意要从1开始,结束为m+1
????????????for?j?in?range(1,n+1):
????????????????dp[i][j]?=?max?(dp[i-1][j],dp[i][j-1])?+?grid[i-1][j-1]
????????return?dp[-1][-1]
代码二:
class?Solution:
????def?maxValue(self,?grid:?List[List[int]])?->?int:
????????m?=?len(grid)
????????n?=?len(grid[0])
????????dp?=?[0]*(n+1)????#(n+1)的数组
????????for?i?in?range?(1,m+1):???#注意要从1开始,结束为m+1
????????????for?j?in?range(1,n+1):
????????????????temp?=?dp[j] #这个也可省略,因为是循环更新,可以代表d[i-1][j]
????????????????dp[j]?=?max?(temp,dp[j-1])?+?grid[i-1][j-1]
????????return?dp[-1]
参考文章:
以上是关于DP-03动态规划算法题目解析的主要内容,如果未能解决你的问题,请参考以下文章