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

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];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值