[LeetCode]三角形最小路径和

题目

三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

说明:

如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

思路

动态规划

参考资料

参考分析。http://www.cnblogs.com/themo/p/3688925.html

  1. 题图要表达的从顶部到底部的最短路径和,其中路径一词有玄机。路径表示上边节点到下一层的两个分叉。如上例,存在的路径只有:2364,2361,2351,2358,2451,2458,2478,2473

  2. 明白题意后,即想到这是一个动态规划问题。思考下转移方程。

f(n,j) = min(f(n-1,j-1),f(n-1,j))+p[i,j]; 貌似有些复杂,我们还得解释一下。

// 转移矩阵
f(n,j) = min(f(n-1 ,j-1), f(n-1 ,j)) + p[n, j];
// f(n, j) 表示从1到n行的,以j为终点的最短路径。
// f(n-1, j) 表示从1到n-1行的,以j为终点的最短路径。
// p[n, j] 表示第n行的第j个元素

对于题目中的例子,我们给出他的状态转移方程构造出来的矩阵

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

转移矩阵如下
[
         [2],            a. 填入2
       [5, 6],          b. 5 = 2+36 = 2+4
    [11,10,13],      c. 11 = 5+6, 10 = 5+min(5,6), 13 = 6+7
  [15,11,18,16]    d. 15 = 11+4, 11 = 1+min(11,10), 18 = 8+min(10,13), 16 = 3+13
]
  1. 由上事例可以看出下层的节点的头和尾,因为只有一个直接前驱,所以不需要求min(最小值)这个过程,中间的其余元素都需要比较两个直接前驱中的较小元素。将自身的值和较小元素求和,得到到达自身的最短路径。

  2. 题目要求的最短路径,针对上面的问题,等价的解答是,找出状态转移矩阵最底层f(n,j)的最小值。便求得由顶到底的最短路径长度。

代码

LeetCode上他人提交代码,使用一维数组,对常规动态规划的二维数组进行空间压缩。

public int minimumTotal(List<List<Integer>> triangle) {
    int n = triangle.size();
    if(n==0){
        return 0;
    }
    int []dp = new int[n];
    for(int i=0;i<n;i++){
        dp[i] = triangle.get(n-1).get(i);
    }

    for(int i=n-2;i>=0;i--){
        for(int j=0;j<=i;j++){
            dp[j] = triangle.get(i).get(j) + Math.min(dp[j],dp[j+1]);
        }
    }
    return dp[0];
}

我的代码

package com.wy.LeetCode;

import java.util.ArrayList;
import java.util.List;

public class T120 {

    public static void main(String[] args) {
        List<List<Integer>> lists = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
//        list.add(2);
        list.add(-1);
        List<Integer> list2 = new ArrayList<>();
        list2.add(2);
        list2.add(3);
        List<Integer> list3 = new ArrayList<>();
        list3.add(1);
        list3.add(-1);
        list3.add(-1);
        List<Integer> list4 = new ArrayList<>();
        list4.add(4);
        list4.add(1);
        list4.add(8);
        list4.add(3);

        lists.add(list);
        lists.add(list2);
        lists.add(list3);


        System.out.println(T120.minimumTotal(lists));

    }


    public static  int minimumTotal(List<List<Integer>> triangle) {
        int length = triangle.size();
        if(length==0){
            return 0;
        }
        //构造矩阵
        int [][]dp = new int[length][length];
        List<Integer> list0 = triangle.get(0);
        //对于第一,二行需要特殊处理
        dp[0][0] = list0.get(0);
        for(int i=1;i<length&&i<2;i++){
            List<Integer> list = triangle.get(i);
            for(int j=0;j<list.size();j++){
                dp[i][j] = list.get(j)+dp[i-1][i-1];
            }
        }
        //其他行处理
        for(int i=2;i<length;i++){
            List<Integer> list = triangle.get(i);
            dp[i][0] = list.get(0)+dp[i-1][0];//第一个元素处理
            dp[i][list.size()-1] = list.get(list.size()-1)+dp[i-1][i-1];//最后一个元素处理
            for(int j=1;j<list.size()-1;j++){
                dp[i][j] = Math.min( dp[i-1][j],dp[i-1][j-1]  )+list.get(j);
            }
        }

        //输出矩阵
        for(int i=0;i<dp.length;i++){
            for(int j=0;j<dp[i].length;j++){
                System.out.print( dp[i][j] +" " );
            }
            System.out.println();
        }
        //在矩阵最后一行找到最小数
        int t = length-1;
        int min = dp[t][0];
        for(int i=1;i<dp[t].length;i++){
            if(min>dp[t][i]){
                min = dp[t][i];
            }
        }
        return min;
    }
}

猜你喜欢

转载自blog.csdn.net/fmuma/article/details/80167433