回溯算法/动态规划-不同路径

目录

不同路径

回溯算法思路

动态规划


不同路径

力扣题目链接(opens new window)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:

  • 输入:m = 3, n = 7
  • 输出:28

示例 2:

  • 输入:m = 2, n = 3
  • 输出:3

解释: 从左上角开始,总共有 3 条路径可以到达右下角。

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

示例 3:

  • 输入:m = 7, n = 3
  • 输出:28

示例 4:

  • 输入:m = 3, n = 3
  • 输出:6

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 10^9

回溯算法思路

  1. 创建 Solution 类并定义 uniquePaths 方法,该方法接收矩阵的行数 m 和列数 n,返回不同路径的数量。

  2. uniquePaths 方法中,创建一个大小为 m*n 的矩阵 grid 用于表示走过的路径,创建一个大小为 m*nvisited 数组用于表示当前位置是否已经被访问过。

  3. 调用 backtrack 方法开始回溯搜索不同的路径,并返回搜索到的路径数量。

  4. backtrack 方法中,判断当前位置是否为目标位置,如果是,则找到一条新的路径,路径数量加1。

  5. 判断当前位置是否越界或已经被访问过,如果是,则不能继续走,返回到上一步。

  6. 标记当前位置已经被访问,向右和向下分别搜索一步,并记录不同路径的数量。

  7. 撤销当前选择,回溯到上一步。

  8. main 方法中,创建一个 Solution 实例,传入矩阵的行数和列数,调用 uniquePaths 方法并输出不同路径的数量。

package com.company;

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] grid = new int[m][n];
        boolean[][] visited = new boolean[m][n];
        backtrack(grid, visited, 0, 0, m - 1, n - 1);
        return count;
    }

    public static int count = 0; // 用于记录不同路径数量

    private void backtrack(int[][] grid, boolean[][] visited, int row, int col, int m, int n) {
        if (row == m && col == n) { // 当前位置为目标位置
            count++; // 找到一条新的路径,路径数量加1
            return;
        }
        if (row > m || col > n || visited[row][col]) { // 越界或当前位置已经被访问过,不能继续走
            return;
        }
        visited[row][col] = true; // 标记当前位置已经被访问
        backtrack(grid, visited, row, col + 1, m, n); // 向右走一步
        backtrack(grid, visited, row + 1, col, m, n); // 向下走一步
        visited[row][col] = false; // 撤销当前选择,回溯到上一步
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int m = 3;
        int n = 3;
        int paths = solution.uniquePaths(m, n);
        System.out.println("The number of unique paths from top-left to bottom-right is: " + paths);
    }
}

visited[row][col] = true; // 标记当前位置已经被访问

visited[row][col] = false; // 撤销当前选择,回溯到上一步

可以删去,因为只能向下走或者向右走,又不能回头

时间复杂度很高,大概率超时!

动态规划思路

  1. 确定dp数组下标含义:dp[i][j]表示从起点到坐标(i,j)的不同路径数目。
  2. 递推公式:dp[i][j] = dp[i-1][j] + dp[i][j-1]。因为每次只能往右或者往下走,所以到达(i,j)这个位置的路径数目,等于到达(i-1,j)和到达(i,j-1)的路径数目之和。
  3. 初始化:第一行和第一列上的位置只能沿着一条直线走,所以在这里的路径数目都是1。
  4. 遍历顺序:可以按行或按列遍历,这里按行遍历,从第2行开始到第m行,对于每一行从第2列开始到第n列。
  5. 推导结果:最后返回dp[m-1][n-1],即到达终点的路径数目。
package com.company;

public class Solution {
    /**
     * 1. 确定dp数组下标含义 dp[i][j] 到每一个坐标可能的路径种类
     * 2. 递推公式 dp[i][j] = dp[i-1][j] dp[i][j-1]
     * 3. 初始化 dp[i][0]=1 dp[0][i]=1 初始化横竖就可
     * 4. 遍历顺序 一行一行遍历
     * 5. 推导结果 。。。。。。。。
     *
     * @param m 行数
     * @param n 列数
     * @return 到达右下角的所有路径数量
     */
    public static int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n]; // 定义 dp 数组,记录到每个坐标的可能路径数
        // 初始化 dp 数组,因为对于第一行和第一列,只有一种可能的路径数,即沿着边走
        for (int i = 0; i < m; i++) {
            dp[i][0] = 1;
        }
        for (int i = 0; i < n; i++) {
            dp[0][i] = 1;
        }

        // 逐行计算 dp 数组中的值,从第二行和第二列开始
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1]; // 状态转移方程,到达当前坐标的可能路径数为从上方和左方的路径数之和
            }
        }
        return dp[m-1][n-1]; // 返回到达右下角的可能路径数
    }
    public static void main(String[] args) {
        int m = 3;
        int n = 3;
        int paths = uniquePaths(m, n);
        System.out.println("The number of unique paths from top-left to bottom-right is: " + paths);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当谈到动态规划算法回溯算法和贪心算法时,它们都是解决优化问题的经典算法。下面我会对每个算法进行详细讲解: 1. 动态规划算法(Dynamic Programming): 动态规划算法通常用于解决具有重叠子问题和最优子结构性质的问题。它通过将问题分解为子问题,并利用子问题的解来构建更大规模的问题的解。动态规划算法通常使用一个表格或数组来存储中间结果,避免重复计算。其基本思想是通过保存并重复使用子问题的解来减少计算量。 2. 回溯算法(Backtracking): 回溯算法是一种通过试错的搜索方法,用于求解满足一定条件的所有可能的解。回溯算法通过尝试每一种可能的选择并在达到不可行解时进行回溯,即返回上一层并尝试其他选择。回溯算法通常使用递归来实现,它能够穷尽所有可能的解空间,并找到满足条件的解。 3. 贪心算法(Greedy Algorithm): 贪心算法是一种通过每一步的局部最优选择来构建整体最优解的算法。贪心算法在每个步骤上都选择当前最优的解,而不考虑整体未来的结果。它通常不会回溯或重新评估之前的选择。贪心算法适用于一些特定类型的问题,如最小生成树、最短路径等,但并不适用于所有问题。 这三种算法各有优势和局限性,选择哪种算法取决于问题的性质和要求。动态规划算法通常适用于具有重叠子问题和最优子结构的问题,回溯算法适用于穷尽搜索所有可能解的问题,而贪心算法适用于局部最优解构成整体最优解的问题。在选择算法时,需要根据问题的特点和约束进行综合考虑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值