本文參考自《劍指offer》一書,代碼采用Java語言。
題目
在一個m×n的棋盤的每一格都放有一個禮物,每個禮物都有一定的價值(價值大於0)。你可以從棋盤的左上角開始拿格子里的禮物,並每次向左或者向下移動一格直到到達棋盤的右下角。給定一個棋盤及其上面的禮物,請計算你最多能拿到多少價值的禮物?
思路
動態規划:定義f(i,j)為到達(i,j)位置格子時能拿到的禮物總和的最大值,則有:f(i,j)=max{f(i,j),f(i,j)}+values(i,j)。
同上道題一樣,如果直接使用遞歸會產生大量的重復計算,因此,創建輔助的數組來保存中間計算結果。
輔助數組不用和m*n的二維數組一樣大,只需要保存上一層的最大值就可以。代碼中使用長度為列數n的一位數組作為輔助數組,注釋部分為二維輔助數組。
輔助數組只需要存 √ 的部分
測試算例
1.功能測試(多行多列,一行多列,多行一列,一行一列)
2.特殊測試(null)
Java代碼
//題目:在一個m×n的棋盤的每一格都放有一個禮物,每個禮物都有一定的價值 //(價值大於0)。你可以從棋盤的左上角開始拿格子里的禮物,並每次向左或 //者向下移動一格直到到達棋盤的右下角。給定一個棋盤及其上面的禮物,請計 //算你最多能拿到多少價值的禮物? public class MaxValueOfGifts { public int maxValueOfGifts(int[][] values) { if(values==null || values.length<=0 ||values[0].length<=0) return 0; int rows=values.length; int cols=values[0].length; // int[][] maxValue=new int[rows][cols]; int[] maxValue=new int[cols]; for(int i=0;i<rows;i++) { for(int j=0;j<cols;j++) { int left=0; int up=0; if(i>0) // up=maxValue[i-1][j]; up=maxValue[j]; if(j>0) // left=maxValue[i][j-1]; left=maxValue[j-1]; // maxValue[i][j]=Math.max(up, left)+values[i][j]; maxValue[j]=Math.max(up, left)+values[i][j]; } } // return maxValue[rows-1][cols-1]; return maxValue[cols-1]; } }
收獲
1.動態規划問題,用公式來表示清楚。
2.動態規划如果有大量重復計算,可以用循環+輔助空間來提高效率。
2.這道題不用二維數組,只需要用一維數組作為輔助空間即可,以后遇到對中間結果的保存問題,看看能否優化輔助空間。