題目來源:力扣
題目描述:
在一個 m*n 的棋盤的每一格都放有一個禮物,每個禮物都有一定的價值(價值大於 0)。你可以從棋盤的左上角開始拿格子裏的禮物,並每次向右或者向下移動一格、直到到達棋盤的右下角。給定一個棋盤及其上面的禮物的價值,請計算你最多能拿到多少價值的禮物?
=============================================
示例 1:
輸入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
輸出: 12
解釋: 路徑 1→3→5→2→1 可以拿到最多價值的禮物
===========================================
審題:
本題屬於一道較簡單的動態規劃類題目.還是按照步驟一步步來分析.剛開始學習動態規劃時,就像小時候解題一樣,一步步理清自己的思路是非常重要的.按步驟慢慢來.
-
分析最優子結構
假設我們當前位於位置(i, j),我們想計算從該位置出發所能拿到的最多價值禮物, 由於我們每一步可以向右移動或向下移動,因此假設我們知道位置(i+1, j)以及位置(i, j+1)處我們所能拿到的最多價值禮物,我們便可以作出判斷,在位置(i, j)處,我們應該向右還是向下移動. 基於該最優子結構,我們進一步分析子問題是否存在重疊. 分析不難發現, 爲了計算(i, j)處最優方案,我們需要計算(i, j+1)處最優方案.而爲了計算(i-1, j+1), 我們同樣需要計算(i, j+1)處最優方案, 因此子問題存在重疊 -
分析狀態變量
該問題狀態變量較爲簡單, 即爲當前所處位置. 由於是二維座標, 因此我們可以使用二維數組存儲每一狀態處的最優方案. S[i][j]表示從位置(i, j)出發, 所能拿到的價值. -
確定狀態轉移方程
其中基礎情形爲
因此, 從左上角出發, 所能獲取的最多價值禮物爲S[0][0];
java算法:
class Solution {
public int maxValue(int[][] grid) {
//狀態變量爲當前位置
int S[][] = new int[grid.length][grid[0].length];
int row = grid.length;
int col = grid[0].length;
//基礎情形
S[row-1][col-1] = grid[row-1][col-1];
for(int i = row-1; i >= 0; i--){
for(int j = col-1; j >= 0; j--){
if(i + 1 < row){
S[i][j] = Math.max(S[i][j], grid[i][j] + S[i+1][j]);
}
if(j+1 < col){
S[i][j] = Math.max(S[i][j], grid[i][j] + S[i][j+1]);
}
}
}
return S[0][0];
}
}
降低空間複雜度值O(1)
在初始版本中,由於我們使用額外的數組S保存各狀態時的最優方案, 因此空間複雜度爲O(MN). 通過分析, 我們發現我們可以直接更改grid[i][j]上的元素, 在計算完(i, j)處最優方案後,使用grid[i][j]儲存位置(i, j)處最優方案.
class Solution {
public int maxValue(int[][] grid) {
//狀態變量爲當前位置
//int S[][] = new int[grid.length][grid[0].length];
int row = grid.length;
int col = grid[0].length;
for(int i = row-1; i >= 0; i--){
for(int j = col-1; j >= 0; j--){
int sum = 0;
if(i + 1 < row){
sum = Math.max(sum, grid[i+1][j]);
}
if(j+1 < col){
sum = Math.max(sum,grid[i][j+1]);
}
grid[i][j] += sum;
}
}
return grid[0][0];
}
}