本博客主要內容爲圖書《劍指offer》第二版47 題的解題思路及代碼。方法可能還有不足之處,歡迎大家討論評論。
1. 題目描述
在一個 m*n 的棋盤中的每一個格都放一個禮物,每個禮物都有一定的價值(價值大於0).你可以從棋盤的左上角開始拿各種裏的禮物,並每次向左或者向下移動一格,直到到達棋盤的右下角。給定一個棋盤及上面個的禮物,請計算你最多能拿走多少價值的禮物?
比如說現在有一個如下的棋盤,
在這個棋盤中,按照(1,12,5,7,7,16,5)的順序可以拿到總價值最大的禮物。
2. 題目分析
我們首先使用遞歸的思路進行分析,當求解到達右下角時禮物的最大總價值時,可以通過如下的遞推關係進行計算
其中
一個很直觀的想法是,我們將每一步求解出的結果都保存在一個矩陣中。那麼在這個問題中就要有一個和原始矩陣等大的矩陣進行存儲,但是實際上只需要一個與列數相同維數的一維數組就夠了。爲什麼存儲這麼少的就夠了呢。
在動態規劃求解這個問題的時候,我們找出到達每一行中每個位置的最大值,在求解第一行的時候,很明顯只能一直向右走,對於第二行的一個數字,很明顯只能從
在上圖中,如果要求到達 a 點的禮物的最大值,它只與左邊的值和它上面的值有關,所以在計算 a 之前就可以將 1 去掉了,因爲後面的計算都不會用到 a 的。同理計算出 a 點的最大值之後就可以將 11 替換掉了,因爲再求 b 的時候不會再用到。分析到這裏我們就可以發現,並不需要一個與原始矩陣等大的矩陣來存儲中間計算的值,只需要一個與列數相同的一維向量即可。
3. 代碼實現
class Solution:
def getmaxValue(self, values, rows, cols):
if not values or rows<=0 or cols <=0:
return 0
# 用於存放中間數值的臨時數組
temp = [0] * cols
for i in range(rows):
for j in range(cols):
left = 0
up = 0
if i > 0:
up = temp[j]
if j > 0:
left = temp[j-1]
temp[j] = max(up,left) + values[i*rows+j]
return temp[-1]
s = Solution()
a = s.getmaxValue([1,10,3,8,12,2,9,6,5,7,4,11,3,7,16,5],4,4)
參考文獻
- 何海濤. 劍指Offer.第2版[M]. 電子工業出版社, 2014.