Leetcode 62. 不同路径【暴搜 + 记忆化搜索 + DP +详解】

不同路径

思路:暴搜:

从起点搜到终点:

  1. 递归的出口:起点为 (0,0),终点为(n,m),所以递归的出口是,二者坐标相等!另外就是边界问题,存在无限向下递归或向右一直递归越界的问题,所以需要判断边界,当前是返回还是继续往前走!
  2. 递归的参数:当前坐标(x, y),由于题目不是全局变量,那就再加上终点坐标(m,n);
  3. 递归体:dfs (x+1, y) , dfs (x, y+1);
class Solution {
public:

    int dfs (int x, int y, int m, int n)
    {
        if (x == m-1 && y == n-1){
            return 1;
        }

        int sum=0;
        if (x+1 <= m-1){
            sum += dfs (x+1, y, m, n);
        }
        if (y+1 <= n-1){
            sum += dfs (x, y+1, m, n);
        }
        return sum;
    }

    int uniquePaths(int m, int n) {
        return dfs (0, 0, m, n);
    }
};

记忆化搜索:

上述暴搜的代码中不知道大家有没有观察到这么一个变量!即:

int sum=0;
 sum += dfs (x+1, y, m, n);
 sum += dfs (x, y+1, m, n);

sum记录的是从当前点到达终点的路径数;即从 (x,y)到达(m,n)的路径数目!那么我们可以开一个记忆化数组去记录当前点到达终点的路径数,毕竟sum是局部变量,只在当前函数内有效!
记忆化搜索的本质就是标记这个点的是否走过了,再走一次也是同样的结果!所以无需再走,直接查表,取出答案。去除重复!

注意:
关键点:本题的记忆化搜索是:加等于的形式,而有些记忆化搜索是 memo[x][y] = dfs (…);

memory[x][y] += dfs(x+1, y, m, n, memory);
 memory[x][y] += dfs (x, y+1, m, n, memory);

两者的区别是:
+= :如图所示:紫色路线是之前走过的,而绿色路线是当前走的,现在绿色路线走到了之前已经走过的位置,而经过查表可知,这个位置到达终点的路径只有一条,所以直接返回1,因为从绿色路线去走到这个位置,再往下走的话,不也还是只有一条路线吗?何必呢?有人说如果查表得到的是3呢?即这个相遇位置到达终点的路线有3条,那还不是一样的吗,我绿色路线走到这个位置,然后从这个位置开始往下走,不也会走出同样的三条路线出来吗?何必呢?所以直接查表返回该点到终点的路径数目。
然后观察可得:绿色线和紫色线虽然从相遇点开始到终点的路线相同,但是之前的不同啊,只要有一个点不同,就不是一个方案:比如序列【1,2,1】和【2,1,1】是同一个方案吗??NO!所以说由于之前的路线不同,所以二者不是同一条路线,所以是 += !!!
Leetcode 62. 不同路径【暴搜 + 记忆化搜索 + DP +详解】_第1张图片

class Solution {
public:

    int dfs (int x, int y, int m, int n, vector<vector<int>>& memory)
    {
        if (memory[x][y] != 0)
            return memory[x][y];
        if (x == m-1 && y==n-1)
        {
            memory[x][y] = 1;
            return memory[x][y];
        }

        if (x+1 <= m-1){
            memory[x][y] += dfs(x+1, y, m, n, memory);
        }
        if (y+1 <= n-1){
            memory[x][y] += dfs (x, y+1, m, n, memory);
        }
        return memory[x][y];
    }

    int uniquePaths(int m, int n) {
        vector<vector<int>> memo(m + 1, vector<int>(n + 1, 0));
        return dfs (0, 0, m, n, memo);
    }
};

思路:动态规划

定义状态:dp[i][j] 表示从起点(0,0)到达(i,j)位置的路径数目。

状态转移:对于每个位置(i,j),可以从(i-1,j)或者(i,j-1)到达,因此到达(i,j)位置的路径数目为到达(i-1,j)位置的路径数目加上到达(i,j-1)位置的路径数目,即dp[i][j] = dp[i-1][j] + dp[i][j-1]。

边界条件:对于第一行和第一列上的每个位置,由于只能往右或往下走,因此到达这些位置只有一条路径,即dp[i][0] = dp[0][j] = 1。

最终结果:dp[m-1][n-1] 表示从起点到终点的路径数目。

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] f = new int[m+1][n+1];

        f[1][1] = 1;
        for (int i=1; i <= m; i ++) 
            for (int j=1; j <= n; j ++)
                if (i == 1 && j == 1) 
                    continue;
                else f[i][j] = f[i-1][j] + f[i][j-1];
                
        return f[m][n];
    }
}

推荐题解!

你可能感兴趣的:(力扣,3000,题,动态规划,算法,leetcode)