leetcode62. 不同路径(动态规划-java)

不同路径

  • leetcode62. 不同路径
    • 题目描述
    • 暴力递归
      • 代码演示
    • 递归加缓存
      • 代码演示
    • 动态规划
      • 代码演示
  • 动态规划专题

leetcode62. 不同路径

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/unique-paths

题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?

示例1:
leetcode62. 不同路径(动态规划-java)_第1张图片
输入:m = 3, n = 7
输出:28

示例 2:
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向下

示例 3:
输入:m = 7, n = 3
输出:28

示例 4:
输入:m = 3, n = 3
输出:6

暴力递归

做动态规划的题时,如果无法一眼看出状态转移方程,就先写出暴力递归的尝试,然后改写暴力递归,把暴力递归改写成动态规划的难度,会比直接写动态规划的难度等级降一级.
这题的暴力递归还是比较容易写的,只有向下和向右两个方向做出选择,两个方向不同的情况相加就是总的情况.在写递归时,注意越界情况的处理.
还有一个注意事项,左上角是从(1,1)开始到(m,n)的.

代码演示

	/**
	* 主方法调用
	*/
	 public int uniquePaths(int m, int n) {
	 	//左上角位置是1,1
     	  return process(m,n,1,1);
	 }
	/**
	* 暴力递归
	* i 和 j 来标记来到的位置
	*/
    public int process (int m,int n,int i ,int j){
    	//来到最后一个位置,返回1,前面走的路径有效
        if(i == m && j == n ){
            return 1;
        }
        //越界时,路径选择无效返回0
        if(i > m || j > n){
            return 0;
        }
        //向下走
        int down = process(m,n,i + 1,j);
        //向右走
        int right = process(m,n,i,j + 1);
        //返回两种情况之和
        return down + right;
    }

递归加缓存

j解决递归中的重叠子问题,减少计算,一般情况下,递归加缓存的效率和动态规划的效率是一样的,能写到递归加缓存,就可以了.

代码演示

/**
* 主方法调用
*/
  public int uniquePaths1(int m, int n) {
  	//缓存表
        int[][]dp = new int[m+1][n+1];
       return process2(m,n,1,1,dp);
    }
    /**
    * 加缓存 去除重复计算
    * dp 缓存表
    */
  public int process2 (int m,int n,int i ,int j,int[][]dp){
        if(i == m && j == n ){
            return 1;
        }
        if(i > m || j > n){
            return 0;
        }
        //缓存有值直接从缓存中拿
        if(dp[i][j] != 0){
            return dp[i][j];
        }
        int down = process2(m,n,i + 1,j,dp);
        int right = process2(m,n,i,j + 1,dp);
        //结果存在缓存中
        dp[i][j] = down + right;
        return down + right;
    }

动态规划

这题可以从底向上去推.
从递归中的base case 中可以知道.最右下角是1.我们还可以知道最底下一行,无法向下走,只能向右,所以都是1.最右边一列,无法向右走,只能向下走,所以方法数也是1.
如图演示:
leetcode62. 不同路径(动态规划-java)_第2张图片
最后一行和最后一列都是1,再看x 位置如何得出:
根据暴力递归中,.
int down = process2(m,n,i + 1,j,dp);
int right = process2(m,n,i,j + 1,dp);
//结果存在缓存中
dp[i][j] = down + right;
可以看出x 位置依赖两个画三角符合的位置,因此可以得出状态转移方程是:
dp[i][j] = dp[i + 1][j] + dp[i][j + 1];
下面就可以写代码了:

代码演示

/**
* 动态规划
*/
  public int uniquePaths(int m, int n) {
        int[][]dp = new int[m+1][n+1];
		//初始化最后一行
        for (int i = 1; i <= n;i++){
            dp[m][i] = 1;
        }
        //初始化最后一列
        for (int i = 1; i <= m;i++){
            dp[i][n] = 1;
        }
		
        for (int i = m - 1;i >= 0;i--){
            for (int j = n - 1; j >= 0;j-- ){
            //状态转移方程
                dp[i][j] = dp[i + 1][j] + dp[i][j + 1];
            }
        }
        return dp[1][1];
    }

动态规划专题

leetcode877. 石子游戏

leetcode64. 最小路径和

leetcode416. 分割等和子集

leetcode354. 俄罗斯套娃信封问题

leetcode300. 最长递增子序列

leetcode337. 打家劫舍 III

你可能感兴趣的:(数据结构,java,算法,动态规划,java,算法,leetcode,数据结构)