暴力递归转动态规划(十)

news/2024/6/2 1:50:01 标签: 动态规划, 算法, 暴力递归

题目
给定一个二维数组matrix[][],一个人必须从左上角出发,最终到达右下角,沿途只可以向下或者向右走,沿途的数字都累加就是距离累加和。返回最小距离累加和。
这道题中会采用压缩数组的算法来进行优化

暴力递归
暴力递归方法的整体思路是根据小人所在的位置(当前值),通过向下传递(向左走向右走)来获取最终选择路径的最小值。
所以base case可以确定:

  1. 如果小人走到了最后一行,那么接下来就只能向下走。
  2. 如果小人走到了最后一列,那么接下来就只能向左走。
  3. 如果小人走到了matrix[][]的最后一个格子,返回当前值给上层做处理,取最小值。
  4. 否则,既可以向左也走可以向右走,并获取最小值。

所以暴力递归的方法就出来了。

public static int minPathSum1(int[][] matrix) {

        if (null == matrix || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
            return -1;
        }

        int row = matrix.length;
        int col = matrix[0].length;

        return process(row - 1, col - 1, 0, 0, matrix);
    }

    //返回 matrix[i...][j....] 位置的最小值。
    public static int process(int row, int col, int curRow, int curCol, int[][] matrix) {
        //当走到最后一个位置,返回matrix中最后一个位置的值
        if (curRow == row && curCol == col) {
            return matrix[row][col];
        }
        //走到最后一行,只能往右走,只能向右累加
        if (curRow == row) {
            return matrix[curRow][curCol] + process(row, col, curRow, curCol + 1, matrix);
        }

        //走到最后一列,只能向下走
        if (curCol == col) {
            return matrix[curRow][curCol] + process(row, col, curRow + 1, curCol, matrix);
        }

        //否则,可以向右走,可以向下走,进行累加。
        int curValue = matrix[curRow][curCol];

        int p1 = curValue + process(row, col, curRow + 1, curCol, matrix);

        int p2 = curValue + process(row, col, curRow, curCol + 1, matrix);

        return Math.min(p1, p2);
    }

动态规划
这道题的动态规划也不难,给定的是一个二维数组matrix[][],每次行和列会进行变化(可变参数),所以可以创建一个和matrix大小相等的dp[][]来存放每一步计算的值。
因为只可以向下走或向右走,所以dp中任选一个格子的依赖是依赖自己的左侧的值和上面的值。其中dp中第一行的值只会依赖同行左侧的值,dp中第一列的值只会依赖同一列上面的值
所以先将dp中第一行和第一列的值填充好后,其余的按照依赖关系填充,即可完善dp表。

代码

 public static int dp(int[][] matrix) {
        if (null == matrix || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
            return -1;
        }

        int row = matrix.length;
        int col = matrix[0].length;
        int[][] dp = new int[row][col];

        dp[0][0] = matrix[0][0];
        for (int i = 1; i < col; i++) {
            dp[0][i] = dp[0][i - 1] + matrix[0][i];
        }

        for (int j = 1; j < row; j++) {
            dp[j][0] = dp[j - 1][0] + matrix[j][0];
        }

        for (int i = 1; i < row; i++) {
            for (int j = 1; j < col; j++) {
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + matrix[i][j];
            }
        }
        return dp[row - 1][col - 1];
    }

优化
动态规划方法中是创建了一个和matrix[][]大小相等的dp表,通过填充dp表来完善的代码。

如果给定的matrix[][]太大了,是不是我的dp表也要跟着很大,并且,在填充dp表时,第三行依赖第二行的值,第四行依赖第三行的值,此时。第二行的值就已经没有用了,不再需要它了,所以是不是只需要一个跟matrix[][]中列的长度相等的一维数组arr[]就够了。

先根据matrix[][]中第0行的值填充arr[],下面的两层循环中,最外层循环会让arr[0]每次加matrix中当行行的第一个值(因为只依赖上面)。内层循环,会找需要依赖的上面值(arr[j])和左边值(arr[j - 1])来取最小值,后加上matrix中当前位置上的值。

代码

 public static int minPathSum2(int[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
            return 0;
        }
        int row = matrix.length;
        int col = matrix[0].length;
        int[] arr = new int[col];
        arr[0] = matrix[0][0];
		//根据matrix第一行的值填充arr
        for (int i = 1; i < col; i++) {
            arr[i] = arr[i - 1] + matrix[0][i];
        }
        
        for (int i = 1; i < row; i++) {
            arr[0] += matrix[i][0];
            for (int j = 1; j < col; j++) {
            //arr[j - 1] : 相当于我依赖的左边
            //arr[j]  : 因为此时arr[j]的值还没修改,还是上一行的值,相当于自己的上面。 
                arr[j] = Math.min(arr[j - 1], arr[j]) + matrix[i][j];
            }
        }
        return arr[col - 1];
    }

http://www.niftyadmin.cn/n/5092094.html

相关文章

gitlab自编译 源码下载

网上都是怎么用 gitlab&#xff0c;但是实际开发中有需要针对 gitlab 进行二次编译自定义实现功能的想法。 搜索了网上的资料以及在官网的查找&#xff0c;查到了如下 gitlab 使用 ruby 开发。 gitlab 下载包 gitlab/gitlab-ce - Packages packages.gitlab.com gitlab/gitl…

测试中Android与IOS分别关注的点

目录 1、自身不同点 2、测试注重点 3、其他测试点 主要从本身系统的不同点、系统造成的不同点、和注意的测试点做总结 1、自身不同点 研发商&#xff1a;Adroid是google公司做的手机系统&#xff0c;IOS是苹果公司做的手机系统   开源程度&#xff1a;Android是开源的&a…

如何在 Protocol Buffers (Proto) 文件中弃用一个字段

前言 Protobuf(Protocol Buffers)是一种跨平台、跨语言的结构化数据存储格式,被广泛用于网络通信和数据存储等领域。Protobuf通过.proto文件进行数据描述,这些文件可以用于生成各平台的数据访问类。 在实际开发中&#xff0c;我们经常会遇到不再使用或者需要替换的字段&#…

Redis常用数据类型、Redis常用命令

Redis常用数据类型、Redis常用命令&#xff1a; Redis常用数据类型&#xff1a;1. 字符串String 类型2. 哈希hash 类型3. 列表list 类型4. 集合set 类型5. 有序集合sorted set / zset 类型 Redis常用命令&#xff1a;1. 字符串操作命令2. 哈希操作命令3. 列表操作命令4. 集合操…

覆盖率分析汇总

1、GCOV覆盖率分析 2、ASAN地址消毒GCOV覆盖率分析 3、AFL模糊测试GCOV覆盖率分析

参数解析(牛客)

目录 一、题目 二、代码 一、题目 二、代码 #include <iostream> #include <vector> using namespace std;int main() {string s;getline(cin, s);int i 0;vector<string>ret;while (i < s.size()){if (s[i] )//遇到空格直接跳过{i;}else if (s[i] …

软考 系统架构设计师系列知识点之基于架构的软件开发方法ABSD(1)

所属章节&#xff1a; 第7章. 系统架构设计基础知识 第2节. 体系结构的设计方法概述 1. 体系结构的设计方法概述 ABSD&#xff0c;全称是Architecture-Based Software Design&#xff0c;中文译为基于体系结构的软件设计。ABSD方法是由体系结构驱动的&#xff0c;即指由构成体…

【数据结构】算法、时间复杂度和空间复杂度详解 ------ 算法篇

文章目录 &#x1f4cb;前言一. ⛳️算法的定义二. ⛳️算法的特性2.1 输入输出2.2 输入输出2.3 有穷性2.4 确定性2.5 可行性 三. ⛳️算法设计要求3.1 正确性3.2 可读性3.2 健壮性3.3 时间效率高和存储量低 四. ⛳️算法效率的度量方法4.1 事后统计方法4.2 事前分析估算方法 五…