递归+动态规划 矩阵最小路径和

本文介绍了一种寻找矩阵中从左上角到右下角的最小路径和的算法,通过两种不同的动态规划方法实现,包括时间和空间复杂度的讨论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.lyk.kk;

/**
 * Created by Administrator on 2017/9/7.
 * 矩阵的最小路径和
 * 给定一个矩阵m,从左上角开始每次只能向右或者向下走,最后到达左下角的位置,路径上所有数组的累加起来就是路径和,返回所有路径中最小的路径和
 * 如果给定的m如下
 * 1 3 5 9
 * 8 1 3 4
 * 5 0 6 1
 * 8 8 4 0
 * 解答。经典动态规划方法。假设矩阵m的太小为M*N,行数为M,列数为N,先生成太小和m一样的矩阵dp.
 * dp[i][j]的值表示从左上角(即(0,0))位置走到(i,j)位置的最小路径和。
 */
public class A4  {
    //第一种方法  时间复杂度O(M*N)  额外空间复杂度为(M*N)
    public int minPathSum1(int [][]m){
        if(m==null||m.length==0||m[0]==null||m[0].length==0){
            return 0;
        }
        int [][]dp=new int[m.length][m[0].length];
        dp[0][0]=m[0][0];
        for(int i=1;i<m.length;i++){
            dp[i][0]=dp[i-1][0]+m[i][0];
        }
        for(int j=1;j<m[0].length;j++){
            dp[0][j]=dp[0][j-1]+m[0][j];
        }
        for(int i=1;i<m.length;i++){
            for(int j=1;j<m[0].length;j++){
                dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+m[i][j];
            }
        }
        return dp[m.length-1][m[0].length-1];
    }

    //第二种方法
    /**
     * 1.动态规划经过空间压缩后的方法。使用太小为min{M,N}的arr数组。额外时间复杂度为O(min{M,N})
     *生成长度为4的数组arr,初始时arr=[0000].我们知道从(0,0)位置到达m中第一行的每个位置,最小的了路径和就是从(0,0)位置的值开始依次累加的结果,所以依次
     * 把arr设置为arr=[1 4 9 18],此时arr[j]的值代表从(0,0)位置到达(0,j)位置的最小路径和。
     * 2.步骤1中arr[j]的值代表从(0,0)位置到达(0,j)位置的最小路径和,在这一步中
     * 想把arr[j]的值更新成从(0,0)到(1,j)的最小路径和。
     * 首先来看arr[0],更新之前arr[0]代表从(0,0)位置到达(0,0)位置的最小路径和(dp[0][0]).
     * 如果想把arr[0]更新成从(0,0)位置到达(1,0)位置的最小路径和(dp[1][0])arr[0]=arr[0]+m[1][0];=9
     * 然后在来看arr[1],更新之前arr[1]的值代表从(0,0)位置到达(0,1)位置的最小路径和(dp[0][1]),
     * 更新之后想让arr[1]代表从(0,0)位置到达(1,1)位置的最小路径和dp[1][1].
     * 根据动态规划的求解过程,到达(1,1)位置有两种选择。一种是从(1,0)位置到达(1,1)位置(dp[1][0]+m[1][1]),
     * 另外一种从(0,1)位置到达(1,1)位置(dp[0][1]+m[1][1]),应该选择路径最小的那个。
     * 3.重复步骤2的更新过程,一直到arr彻底变成dp矩阵的最后一行。整个过程其实就是不断滚动更新arr数组,
        让arr一次变成dp矩阵每一行的值。最终变成dp矩阵最后一行的值。
     
     */
    public int minPathSum2(int [][]m){
        if(m==null||m.length==0||m[0]==null||m[0].length==0){
            return 0;
        }
        int more=Math.max(m.length,m[0].length);//行,列 中大的那一方
        int less=Math.min(m.length,m[0].length);//行,列 中小的那一方
        boolean rowmore=more==m.length;//行数是不是等于列数
        int [] arr=new int [less];
        arr[0]=m[0][0];
        for(int i=1;i<less;i++){
            arr[i]=arr[i-1]+(rowmore?m[0][i]:m[i][0]);
        }
        for(int i=1;i<more;i++){
            arr[0]=arr[0]+(rowmore?m[i][0]:m[0][i]);
            for(int j=1;j<less;j++){
                arr[j]=Math.max(arr[j]-1,arr[j])+(rowmore?m[i][j]:m[j][i]);
            }
        }
        return arr[less-1];
    }
}
### 寻找矩阵最小路径问题的递归解法 对于给定的一个 m×n 的网格 `grid`,目标是从左上角走到右下角,并使所经过路径上的数值总最小。每次移动只能向下或向右。 #### 递归方法解析 为了计算从起点到终点的最短路径,在任意位置 `(i,j)` 处的最优解等于当前位置的值加上其下方 `(i+1,j)` 或右侧 `(i,j+1)` 中较小的那个位置的最佳路径[^1]: ```c #include <limits.h> #include <stdio.h> int minPathSumUtil(int grid[][3], int row, int col, int m, int n); // 辅助函数用于返回两个整数之间的最小值 int min(int x, int y) { return (x < y)? x : y; } // 主要功能:求取从(0,0)到达(m-1,n-1)处的最小路径 int minPathSum(int grid[][3], int m, int n){ // 调用辅助函数并传入初始坐标以及行列大小参数 return minPathSumUtil(grid, 0, 0, m, n); } // 实际执行递归逻辑的功能定义 int minPathSumUtil(int grid[][3], int row, int col, int m, int n){ // 如果越界则返回极大值表示不可达 if(row >= m || col >= n) return INT_MAX; // 当前格子就是目的地时直接返回该格子内的权值 if(row==m-1 && col==n-1) return grid[row][col]; // 否则选择下一步往右边走还是往下边走更优的结果再加上当前节点权重作为最终结果返回 return grid[row][col] + min(minPathSumUtil(grid, row+1, col, m, n), minPathSumUtil(grid, row, col+1, m, n)); } ``` 此代码片段展示了如何通过递归来解决这个问题。然而需要注意的是这种方法存在大量的重复计算,因此效率较低。可以考虑采用记忆化技术来优化性能,即将已经计算过的中间状态保存起来以便后续重用[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值