研究了一会,贴上Triangle的Dynamic Programming的解法。
Dynamic Programming的解题其实一般有四个关键点:
1.定义:一般DP问题都是求出一个最优解,所以你首先要定义出一个最优解的定义。在这道题中设OPT[i][j]为从点( i,j )到顶点Triangle[0][0]的最短距离,当然解决问题的方向不一样最优解的定义一般也不一样。我这里选的是从上往下的解法。
2.初始化:或者可以理解为 OPT[i][j]的特殊值。在这里我们可以知道顶点的Opt的值就是顶点自己本身的值。所以有OPT[0][0]=Triangle[0][0]。
3.动态规划DP方程: 其实第三部是解决所有DP问题的核心也是最难的地方,一般动态规划方程想对了一般DP的问题就如砍瓜切菜一样简单。当时候自己在上570算法课的时候DP问题始终想不明白。现在在OJ上跑到真题之后才发现其实DP问题就和状态机一样,总是由前几个状态决定下一个状态。在Triangle中对与OPT最优解数组中的任意一个点OPT[i][j],如果最优解路径经过了这个点有且仅可能是由两种情况:要么从正上方的点OPT[i-1][j]往下走,要么是从左上方的点OPT[i-1][j-1]往右下方走。所以两种情况的路径值分别是到该两点的最短路径值加triangle[j][j]。然后再取最小值。所以我们可以得到DP方程:
OPT[i][j] = Math.min( OPT[i-1][j-1]+triangle[i][j],OPT[i-1][j]+triangle[i][j]);
4取最优值:在第一步和第三步中我们就应该明白我们的DP程序最后完成时是走到哪一步,这样我们可以清晰的知道我们的最优解在什么地方取得。在这个方法中最后我们得到了OPT[][]数组中从顶点到最底下一排节点的各个OPT值我们再在这些值中取最小值就是这道题的解法。
public class Solution {
/**
* @param triangle: a list of lists of integers.
* @return: An integer, minimum path sum.
*/
int best = Integer.MAX_VALUE;
public int minimumTotal(int[][] triangle) {
// write your code here
if(triangle == null || triangle.length == 1){
return triangle[0][0];
}
int i = triangle.length;
int[][] OPT = new int[i][i];
//Initialization
OPT[0][0] = triangle[0][0];
for( int m = 1; m<i; m++ ){
OPT[m][0] = OPT[m-1][0] + triangle[m][0];
OPT[m][m] = OPT[m-1][m-1] + triangle[m][m];
}
//DP formula
for ( int m = 1;m<i;m++ ){
for( int k = 1; k<m;k++){
OPT[m][k] = Math.min( OPT[m-1][k-1]+triangle[m][k],OPT[m-1][k]+triangle[m][k]);
}
}
//find the minium
int best = OPT[i-1][0];
for(int k = 1; k<i; k++){
best = Math.min(OPT[i-1][k],best);
}
return best;
}
}
时间复杂度:25行到29行的两个for循环产生了最大的时间复杂度O(n^2)所以这道题的时间复杂度就为O(n^2)。其实我们在求出最优解OPT的时候实际上是遍历了这个二维数组的所有元素。triangle一共有(1+2+3+………+n)个元素,根据Big O定律,时间复杂度也是O(n^2).