DP-03动态规划算法题目解析

Posted yifanrensheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP-03动态规划算法题目解析相关的知识,希望对你有一定的参考价值。

目录

  1. 面试题14- I. 剪绳子/343. 整数拆分
  2. 面试题42. 连续子数组的最大和/53. 最大子序和
  3. 面试题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]

参考文章:

1https://leetcode-cn.com/

以上是关于DP-03动态规划算法题目解析的主要内容,如果未能解决你的问题,请参考以下文章

DP-02动态规划算法题目解析

区间型动态规划题目解析

深度解析「正则表达式匹配」:从暴力解法到动态规划

动态规划

算法题套路总结(三)——动态规划

动态规划分析总结——怎样设计和实现动态规划算法