LeetCode 数组:62. 不同路径(动态规划 带记忆的递归)

,接下来

 

 

在没有接触过动态规划之前,是这样思考这个题的。

首先想到的就是递归中青蛙跳台阶的问题,自然想到递归。就使用原函数 int uniquePaths(int m, int n)

  • 函数的作用,遵循规则的情况下,有多少中途径到达坐标为(m-1,n-1)的位置
  • 递归终止条件:原点(m=n=1),函数返回1,如果m==0||n==0也是返回1(只有一种)
  • 递归关系:uniquePaths(m,n)=uniquePaths(m-1,n)+uniquePaths(m,n-1)

代码完成如下:

class Solution {
    public int uniquePaths(int m, int n) {
        if(m==1||n==1)
        {return 1;}

        return uniquePaths(m-1,n)+uniquePaths(m,n-1);
    }
}

 

然而超时了。。。

递归有重复计算的问题,在很多格子中,明明曾经已经计算过结果,但是碰到仍然向后继续递归了:

加一个数组,用于保存已经计算的结果

class Solution {
    int[][] dp = new int[100][100];
    public int uniquePaths(int m, int n) {
        return cycle(m-1,n-1);
    }
    public int cycle(int i,int j){
        if(i == 0 || j == 0) return 1;
        if(dp[i][j] != 0) return dp[i][j];
        dp[i][j] = cycle(i-1,j)+cycle(i,j-1);
        return dp[i][j];
    }
}

通过接下来看动态规划的算法。

动态规划是正着推,而且有一个用于存放结果的一维/二维数组,大部分问题是二维的。

首先需要确认该问题是否符合动态规划解题要求
动态规划适合解决的问题模型符合"一个模型三个特性"
一个模型可以概括为:多阶段决策最优解模型; 本题目第一行是已经定好了都是1,
在第二行的时候,每个方格的值都是该方格左边的格和该方格上边的格的总和,以此类推,满足.
  • 特性1:最优子结构;每个阶段的状态或值都是通过前面阶段的状态或值推导出来的,满足.
  • 特性2:无后效性;每个阶段的状态值一旦确定之后,是不受后面阶段状态值所影响的,满足.
  • 特性3:重复子问题;从递归解法中就能看出来有重复子问题的计算,满足.
 
接下来,该分析如何套用动态规划解题步骤
首先,定义二维数组保存路径条数,按照递归中分析得出第一行和第一列都是1,所以二维数组直接定义成如此
然后分阶段阶段,每一横行的处理就是一个阶段,通过上一行就能推导出下一行的状态值
在每一个阶段中,同一行中的方格,是其左边方格的值加上一行方格的总和
最后返回二维数组最后一个元素的值即可.
class Solution {
    public int uniquePaths(int m, int n) {
        int [][] dp = new int[m+1][n+1];
        //
        for(int i = 1;i<m+1;i++){
            //
            for(int j = 1;j<n+1;j++){
                if(i == 1 && j == 1){
                    dp[1][1] = 1;
                }else{
                    //状态转移方程
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        return dp[m][n];
    }
}

这样的时间复杂度和空间复杂度都是om*n

有优化的办法,把空间复杂度优化为O2n或者On

优化一:将一个表优化成了表中我们需要的两行

优化二:在优化一的基础上,将两行优化成了我们需要的当前行,因为cur未更新前保存的结果是上一行的结果

 

另外,这道题其实直接排列组合就能做:

 

posted @ 2020-08-06 12:21  将来的事  阅读(230)  评论(0编辑  收藏  举报