給定一個數字三角形,找到從頂部到底部的最小路徑和。每一步能夠移動到下面一行的相鄰數字上。javascript
好比,給出下列數字三角形:java
2 3 4 6 5 7 4 1 8 3
從頂到底部的最小路徑和爲11 ( 2 + 3 + 5 + 1 = 11)。數組
咱們給每個位置標上座標 2 (0,0) 3 4 (1,0) (1,1) 6 5 7 ... 4 1 8 3 ... 咱們用f(i,j)表示從(i,j)位置一直到三角形底部的最小路徑和。 那麼f(0,0) = min(f(1,0),f(1,1))+Value(0,0); Value(0,0)就是值2 f(1,0) = min(f(2,0),f(2,1))+Value(1,0); ... 1.推導出狀態轉移方程: f(i,j) = min(f(i+1,j),f(i+1,j+1)) + Value(i,j)。 利用這個狀態轉移方程咱們能夠寫出一個遞歸函數。 2.遞歸的邊界肯定: 對於f(i,j),當: i == 三角形高度-1 的時候,直接返回Value(i,j)
(function(){ main(); })(); /** * [三角問題最小路徑和] * @param {[Array]} triangleList [trianglelist] * @return {[Number]} [length of minimumTotal] */ function minimumTotal(triangleList){ //這個DP問題的狀態轉移方程 //f(i,j) = min(f(i+1,j),f(i+1,j+1))+(i,j) f(i,j)表示當前步驟(i,j)走到最後,所對應的最小路徑和 var triangleHeight = getTriangleHeight(triangleList); function calResult(i,j){ if(i == triangleHeight-1){ return triangleList[getIndex_i(i)+j]; }else{ var res1 = calResult(i+1,j); var res2 = calResult(i+1,j+1); return Math.min(res1,res2)+triangleList[getIndex_i(i)+j]; } } return calResult(0,0); } /** * 獲取三角形有多少行 * @param {[Array]} triangleList [description] * @return {[Number]} [description] */ function getTriangleHeight(triangleList){ var height = 0.5*(Math.sqrt(1+triangleList.length*8)-1); console.assert(parseInt(height) == height,"輸入的三角形數據數量有誤"); return height; } /** * 經過行數獲取該行第一個元素在數組中的下標 * @param {[Number]} lineNo [行標,從0開始計] * @return {[Number]} [數組下標] */ function getIndex_i(lineNo){ // if(lineNo == 0) // return 0; // return getIndex_i(lineNo-1)+lineNo; //根據 f(n) = f(n-1)+n; f(0)=0 推到 f(n) = n(n+1)/2 return lineNo*(lineNo+1)/2; } function main(){ var TEMP = [2,3,4,6,5,7,4,1,8,9]; console.log(minimumTotal(TEMP)) }