算法28:力扣64题,最小路径和------------样本模型

题目:

给定一个二维数组matrix,一个人必须从左上角出发,最后到达右下角 。沿途只可以向下或者向右走,沿途的数字都累加就是距离累加和 * 返回累加和最小值

思路:

1. 既然是给定二维数组matrix,那么二维数组的数据是知道的

2. 这个人只能从左上角出发,目的地是右下角

3. 沿途只能向下或者向右走。那么第一行和第一列的值是可以知道的。

假设这个二维数组是:

|---|---|---|---|
| 3 | 7 | 9 | 6 |
| 6 | 5 | 3 | 9 |
| 8 | 3 | 1 | 5 |
| 4 | 7 | 9 | 2 |

根据这个二维数组推导:

第一行的数据只能往右走,因为它不存在上方数据,依此可以推导出:

|---|----|----|----|
| 3 | 10 | 19 | 25 |
| | | | |
| | | | |
| | | | |

第一列的数据,只能往下走,因为它不存在左边的数据,以此可以推导

|----------|---------|----------|----------|
| 3 | 10(3+7) | 19(10+9) | 25(19+6) |
| 9(3+6) | | | |
| 17(9+8) | | | |
| 21(17+4) | | | |

已经推导出第一行和第一列的数据,接下来开始推导剩下的数据。因为每一个格子的数据都是依赖上一行的当前列或者当前行的前一列的值。谁小,就要谁。以此可以推导出:

|----|--------------------|--------------------|--------------------|
| 3 | 10 | 19 | 25 |
| 9 | 14(9<10取 9+5) | 17(14<19 取14+3) | 26(17<25 取17+9) |
| 17 | 17(14<17 取14+3) | 18 | 23(18<26 取 18+5) |
| 21 | 24 (17<21 取 17+7) | 27 (18<24 取 18+9) | 25 (23<27 取 23+2) |

推导公式已经出来了。下面看代码的实现:

java 复制代码
public static int minSum (int[][] matrix)
    {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        //行数
        int row = matrix.length;
        //列数
        int col = matrix[0].length;

        //如果是100*100规模的二维数组。那么dp的空间开销巨大
        int[][] dp = new int[row][col];

        //dp的第一行值只能依赖左边的值
        dp[0][0] = matrix[0][0];
        //构建dp表的第一行数据
        for (int colIndex = 1; colIndex < col; colIndex++) {
            //前一列和当前列的累加和,放入dp表
            dp[0][colIndex] = dp[0][colIndex -1] + matrix[0][colIndex];
        }

        //构建dp表的第一列数据
        for (int rowIndex = 1; rowIndex < row; rowIndex++) {
            //上一列和当前列的累加和,放入dp表
            dp[rowIndex][0] = dp[rowIndex -1][0] + matrix[rowIndex][0];
        }

        for (int rowIndex = 1; rowIndex < row; rowIndex++) {

            for (int colIndex = 1; colIndex < col; colIndex++) {
                //先获取上一行当前列 与 当前行的前一列 较小的值
                //获取matrix数组的当前行当前列的值
                //两者相加,就是 dp[rowIndex][colIndex]能够得到的最小值
                dp[rowIndex][colIndex] = Math.min(dp[rowIndex][colIndex -1], dp[rowIndex -1][colIndex]) + matrix[rowIndex][colIndex];
            }
        }
        return dp[row-1][col-1];
    }

以上代码是逐步推导的过程。但是,如果一个100行100列的数组需要推导,而且是要右下角的数据,中间数据是没有必要一直存在的。以上的代码浪费了 100*100的空间,并不是一个好的方式:

分析:

1. 第一行的数据是一定要的,因为根据第一行数据可以推导出第二行的数据

2. 第一列的数据是没有必要一次性全部推导出来的,因为每一个格子只依赖上一行的当前列和当前行的前一列。如果移动到当前行,直接更新当前行的第一列即可。

优化的代码:

java 复制代码
//空间压缩进行优化
    public static int minSum2 (int[][] matrix)
    {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        //行数
        int row = matrix.length;
        //列数
        int col = matrix[0].length;

        // 空间压缩。
        // 二维数组变一维数组。
        int[] dp = new int[col];
        //构建dp表的第一行数据
        dp[0] = matrix[0][0];
        for (int colIndex = 1; colIndex < col; colIndex++) {
            //前一列和当前列的累加和,放入dp表
            dp[colIndex] = dp[colIndex -1] + matrix[0][colIndex];
        }

        for (int rowIndex = 1; rowIndex < row; rowIndex++) {
            //当前行第一列数据
            dp[0] += matrix[rowIndex][0];

            for (int colIndex = 1; colIndex < col; colIndex++) {
                 dp[colIndex] = Math.min(dp[colIndex -1], dp[colIndex]) + matrix[rowIndex][colIndex];
            }
        }

        return dp[col -1];
    }

完整代码以及测试结果:

java 复制代码
package code03.动态规划_07.lesson4;

/**
 * 给定一个二维数组matrix,一个人必须从左上角出发,最后到达右下角
 * 沿途只可以向下或者向右走,沿途的数字都累加就是距离累加和
 * 返回累加和最小值
 */
public class MinPathSum_01 {

    public static int minSum (int[][] matrix)
    {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        //行数
        int row = matrix.length;
        //列数
        int col = matrix[0].length;

        //如果是100*100规模的二维数组。那么dp的空间开销巨大
        int[][] dp = new int[row][col];

        //dp的第一行值只能依赖左边的值
        dp[0][0] = matrix[0][0];
        //构建dp表的第一行数据
        for (int colIndex = 1; colIndex < col; colIndex++) {
            //前一列和当前列的累加和,放入dp表
            dp[0][colIndex] = dp[0][colIndex -1] + matrix[0][colIndex];
        }

        //构建dp表的第一列数据
        for (int rowIndex = 1; rowIndex < row; rowIndex++) {
            //上一列和当前列的累加和,放入dp表
            dp[rowIndex][0] = dp[rowIndex -1][0] + matrix[rowIndex][0];
        }

        for (int rowIndex = 1; rowIndex < row; rowIndex++) {

            for (int colIndex = 1; colIndex < col; colIndex++) {
                //先获取上一行当前列 与 当前行的前一列 较小的值
                //获取matrix数组的当前行当前列的值
                //两者相加,就是 dp[rowIndex][colIndex]能够得到的最小值
                dp[rowIndex][colIndex] = Math.min(dp[rowIndex][colIndex -1], dp[rowIndex -1][colIndex]) + matrix[rowIndex][colIndex];
            }
        }
        return dp[row-1][col-1];
    }

    //空间压缩进行优化
    public static int minSum2 (int[][] matrix)
    {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        //行数
        int row = matrix.length;
        //列数
        int col = matrix[0].length;

        // 空间压缩。
        // 二维数组变一维数组。
        int[] dp = new int[col];
        //构建dp表的第一行数据
        dp[0] = matrix[0][0];
        for (int colIndex = 1; colIndex < col; colIndex++) {
            //前一列和当前列的累加和,放入dp表
            dp[colIndex] = dp[colIndex -1] + matrix[0][colIndex];
        }

        for (int rowIndex = 1; rowIndex < row; rowIndex++) {
            //当前行第一列数据
            dp[0] += matrix[rowIndex][0];

            for (int colIndex = 1; colIndex < col; colIndex++) {
                 dp[colIndex] = Math.min(dp[colIndex -1], dp[colIndex]) + matrix[rowIndex][colIndex];
            }
        }

        return dp[col -1];
    }

    public static void main(String[] args) {
        int[][] arr = {
                {3,7,9,6},
                {6,5,3,9},
                {8,3,1,5},
                {4,7,9,2}
        };

        System.out.println(minSum(arr));
        System.out.println(minSum2(arr));
    }

}
相关推荐
Jasmine_llq13 小时前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
爱吃rabbit的mq14 小时前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
(❁´◡`❁)Jimmy(❁´◡`❁)14 小时前
Exgcd 学习笔记
笔记·学习·算法
YYuCChi15 小时前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划
不能隔夜的咖喱15 小时前
牛客网刷题(2)
java·开发语言·算法
VT.馒头15 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
进击的小头16 小时前
实战案例:51单片机低功耗场景下的简易滤波实现
c语言·单片机·算法·51单片机
咖丨喱17 小时前
IP校验和算法解析与实现
网络·tcp/ip·算法
罗湖老棍子17 小时前
括号配对(信息学奥赛一本通- P1572)
算法·动态规划·区间dp·字符串匹配·区间动态规划
fengfuyao98518 小时前
基于MATLAB的表面织构油润滑轴承故障频率提取(改进VMD算法)
人工智能·算法·matlab