不同路径

101 阅读2分钟

题目

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

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

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

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

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

回溯算法

import java.util.ArrayList;
import java.util.List;

public class Main {


    public static void main(String[] args) {

        Main main = new Main();
        main.uniquePaths(3, 2);

    }

    int m = 0;
    int n = 0;
    int count = 0;
    public int uniquePaths(int m, int n) {
        this.m = m;
        this.n = n;
        boolean [][] visited = new boolean[m][n];
        visited[m - 1][0] = Boolean.TRUE;
        huisu(m - 1, 0, visited);

        return count;



    }

    public void huisu(int row, int col, boolean [][] visited) {
        if (row == 0 && col == n - 1) {
            count ++ ;
        }
        // 选择列表
        List<int []> optionList = getOptionList(row, col, visited);
        if (optionList.size() == 0) {
            return;
        }

        for (int [] option : optionList) {
            // 作出选择
            visited[option[0]][option[1]] = Boolean.TRUE;
            huisu(option[0], option[1], visited);

            // 撤销选择
            visited[option[0]][option[1]] = Boolean.FALSE;

        }



    }

    public List<int []> getOptionList(int row, int col, boolean [][] visited) {
        List<int []> optionList = new ArrayList<>();
        // 向下
        if (row - 1 >=0 && col < n && !visited[row - 1][col]) {
            optionList.add(new int[] {row - 1, col});
        }
        // 向右
        if (row >=0 && col + 1 < n && !visited[row][col + 1]) {
            optionList.add(new int[] {row, col + 1});
        }
        return optionList;
    }
    

}

基本思路

  1. 通过回溯算法暴力枚举, 穷举法, 通过记录已走过的位置, 防止走回头路

缺点

  1. 暴力枚举, 矩阵大之后会超时

动态规划


public class Main {


    public static void main(String[] args) {

        Main main = new Main();
        main.uniquePaths(2, 2);

    }

    int m;
    int n;
    int [][] dpTable;
    public int uniquePaths(int m, int n) {
        this.m = m;
        this.n = n;
        dpTable = new int[m][n];
        // 因为只能向右和向下 因此到达某个格子的路径是由它左边的格子和上边的格子走一步得到
        // 即dp[i][j] = dp[i + 1][j] + dp[i][j - 1]
        // 从底向上计算
        for(int i = m - 1; i >=0 ; i --) {
            for (int j = 0; j < n; j ++) {
                dpTable[i][j] = dp(i, j);
            }
        }

        return dpTable[0][n - 1];
    }

    public int dp(int row, int col) {
        if (row >= m || col < 0) {
            return 0;
        }
        if (row == m - 1 && col == 0) {
            // 返回到左上
            return 1;
        }
        if (dpTable[row][col] != 0) {
            return dpTable[row][col];
        }
        return dp(row + 1, col) + dp(row, col - 1);
    }

}

基本思路

  1. 仔细审题后发现, 可以用动态规划的方式利用空间换时间, 更加有效率的穷举.

  2. 发现到达每个格子的路径, 只能由该格子的上一个格子和左边一个格子走一步得到. 即dp[i][j] = dp[i + 1][j] + dp[i][j - 1]

  3. 利用dp table, 自底向上的计算到达每个格子的可能路径, 直到达到目标的格子, 即计算到达(m - 1, 0)格子的, 然后计算(m - 1, 1)和(m - 2, 0)的, 直到计算到(0, n - 1)格子的