LeetCode[62] 不同路径(DP)

本题目算是面试比较常见的了,主要考察对算法的理解,最优的解法是动态规划,本篇写一下本题的动态规划思路和解法。

题目描述

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

示例一:

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

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

示例二:

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

提示:

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

题解思路

  1. 暴力法:使用 DFS 遍历,从 (1,1)-> (m, n),当到达右下角时,计数加一,直到遍历结束。只能解决一部分用例,会执行超时,时间复杂度 O(N^2)
  2. 动态规划:开辟新的状态空间,保存每个点的状态值,该状态值表示到达该点所能走的路数。最终到达右下角时,该点所记录的路数就是总共的不同路径数。因为只需要遍历一次二维数组的状态值,因此时间复杂度为 O(N)
  3. DFS & DP:看到一个有意思的题解,对 dfs 做了优化,使用状态转移方程去除重复计算,因此时间复杂度同 dp
  4. DP最优解法:优化存储空间,使用一维数组存储状态。空间复杂度从 O(m x n)降到 O(n)

  如何求每个点的状态值呢?这个问题就用到了数学归纳法了,观察可得:
  当 m = 1, n = 1 时,起点不用向右和向下就已到达,路数为 1;
  当 m = 1, n = 2 时,起点只能向下一步到达目标点,路数为 1;
  当 m = 2, n = 1 时,起点只能向右一步到达目标点,路数为 1;
  当 m = 2, n = 2 时,起点可以往右一步再往下一步,或者先往下再往右到达目标点,路数为 2;
  当 m = 2, n = 3 时,起点可以往下两步再往右一步,或者到达点(2,2)再往下一步,
  而到达点(2,2)的路数为 2,因此到达目标点的路数总共 为 3;
  以此类推,可以发现规律,到达点(m, n)的路数是(m - 1, n)的路数加(m, n - 1)的路数和,
  即:status[m][n] = status[m - 1][n] + status[m][n-1](状态转移方程)

代码实现

递归代码
int status[101][101] = {0};
int uniquePaths(int m, int n)
{
    if(m <= 0 || n <= 0) {
        return 0;
    }
    if(m == 1 || n == 1) {
        return 1;
    }
    // 当该点状态值 > 0 时,说明已经计算过路径数,无需重复计算
    if(status[m][n] > 0) {
        return status[m][n];
    }
    status[m - 1][n] = uniquePaths(m - 1, n);
    status[m][n - 1] = uniquePaths(m, n - 1);
    status[m][n] = status[m - 1][n] + status[m][n - 1];
    return status[m][n];
}
迭代代码
int uniquePaths(int m, int n)
{
    int status[101][101] = {0};
    int i, j;
    for(i = 1; i <= m; i++) {
        for(j = 1; j <= n; j++) {
            if(i == 1 || j == 1) {
                status[i][j] = 1;
            }
            else {
                status[i][j] = status[i - 1][j] + status[i][j -1];
            }
        }
    }
    return status[m][n];
}
DFS优化解法
int status[101][101];
int dfs(int x, int y) {
    if(x < 1 || y < 1) {
        return 0;
    }
    if(x == 1 || y == 1) {
        return 1;
    }
    if(status[x][y] > 0) {
        return status[x][y];
    }
    status[x][y] = dfs(x - 1, y) + dfs(x, y - 1);
    return status[x][y];
}
int uniquePaths(int m, int n) {
    return dfs(m, n);
}
DP最优解法
int uniquePaths(int m, int n)
{
    int *status = (int *)malloc(sizeof(int) * n);
    int i, j;
    for(i = 0; i < n; i++) {
        status[i] = 1;
    }
    for(i = 1; i < m; i++) {
        for(j = 1; j < n; j++) {
            status[j] += status[j - 1];
        }
    }
    return status[n - 1];
}
posted @ 2020-04-15 00:34  Caso_卡索  阅读(84)  评论(0编辑  收藏  举报