python最少数量的礼物_剑指offer-47礼物的最大价值-python

《剑指offer》python实现系列,全目录

题目描述:

在一个mxn的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0),你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格,直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿多少价值的礼物?

1 10 3 8

12 2 9 6

5 7 4 11

3 7 16 5

1,12,5,7,7,16,5可以拿到最大价值位53的礼物。

第一想法:

动态规划

剑指offer方法:

动态规划

$f( i, j ) $ 表示到达坐标为(i, j) 的格子时,礼物总和的最大值,而只有两种途径没那功能到达(i, j) ,通过格子(i-1, j)或(i,j - 1 ).所以

$f(i, j ) = max(f(i-1, j) , f(i, j - 1)) + gift[i,j]$

还需要一个辅助的二维数组缓存中甲的计算结果,数组中坐标为(i,j)的元素表示到达坐标为(i,j)的格子时能拿到的礼物价值总和的最大值。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20class Solution:

def get_max_value(self, values, rows, cols):

#矩阵左上角按00算

if not values or rows <= 0 or cols <= 0:

return 0

maxValues = [[0]*cols]*rows #辅助数组,保存中间结果

for i in range(rows):

for j in range(cols):

left = 0 #来自左边的礼物最大值

up = 0 #来自上边的礼物最大值

if i > 0:#i>0说明可以来自上边

up = maxValues[i-1][j]

if j > 0:#说明可以来自左边

left = maxValues[i][j-1]

#状态转移方程

maxValues[i][j] = max(up,left)+values[i*cols+j]

return maxValues[rows-1][cols-1] #返回右下角元素

print(Solution().get_max_value([1, 10, 3, 8, 12, 2, 9, 6, 5, 7, 4, 11, 3, 7, 16, 5], 4, 4))

优化

将二位辅助矩阵 改为 一维数组

拿到礼物的最大价值只依赖于(i-1,j)和 (i,j-1)的两个格子,因此可i-2行及更上面的所有格子以及j-2列及更左边的所有各自礼物的最大价值实际上没有必要保存下来。

可以用一个一维数组来替代前面代码中的二维矩阵 max Values。

该一维数组的长度为棋盘的列数n。当我们计算到达坐标为(i,j)的格子时能够拿到

该数组前面j个数字分别是当前第i行前面j个格子礼物的最大价值,而之后的数字分别保存前面第i-1行n-j个格子礼物的最大价值。就是此数组以j位分界线分成两部分,前半部分是当前行前j个元素的最大价值,后半部分是上一行后面(n-j)个元素的最大价值。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22class Solution:

def get_max_value(self, values, rows, cols):

#矩阵左上角按00算

if not values or rows <= 0 or cols <= 0:

return 0

maxValues = [0]*cols

for i in range(rows):

for j in range(cols):

left = 0 #来自左边的礼物最大值

up = 0 #来自上边的礼物最大值

if i > 0:#i>0说明可以来自上边

up = maxValues[j]

if j > 0:#说明可以来自左边

left = maxValues[j-1]

#状态转移方程

maxValues[j] = max(up,left)+values[i*cols+j]

return maxValues[-1] #返回右下角元素

print(Solution().get_max_value([1, 10, 3, 8, 12, 2, 9, 6, 5, 7, 4, 11, 3, 7, 16, 5], 4, 4))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值