代码随想录 day 34 动态规划

第九章 动态规划part02

今天开始逐渐有 dp的感觉了,前 两题 不同路径,可以好好研究一下,适合进阶
详细布置

62.不同路径

本题大家掌握动态规划的方法就可以。 数论方法 有点非主流,很难想到。
https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html
视频讲解:https://www.bilibili.com/video/BV1ve4y1x7Eu

63. 不同路径 II

https://programmercarl.com/0063.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84II.htmlhttps://programmercarl.com/0063.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84II.html
视频讲解:https://www.bilibili.com/video/BV1Ld4y1k7c6

343. 整数拆分 (可跳过)

本题思路并不容易想,一刷建议可以跳过。如果学有余力,可以看视频理解一波。
https://programmercarl.com/0343.%E6%95%B4%E6%95%B0%E6%8B%86%E5%88%86.html
视频讲解:https://www.bilibili.com/video/BV1Mg411q7YJ

96. .不同的二叉搜索树 (可跳过)

本题思路并不容易想,一刷建议可以跳过。 如果学有余力,可以看视频理解一波。
https://programmercarl.com/0096.%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html
视频讲解:https://www.bilibili.com/video/BV1eK411o7QA

62. 不同路径

题目链接

https://leetcode.cn/problems/unique-paths/description/

解题思路

1.确定dp数组以及下标i的含义
** dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径**
** 2.确定递推公式**
** 想要求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]**
** dp[i][j]=dp[i][j-1]+dp[i-1][j];**
** 3.dp数组的初始化**
** 首先dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理**
4.确定遍历顺序
5.举例推导dp数组

code

class Solution {
    //时间复杂度:O(m × n) 空间复杂度O(m x n)
    public int uniquePaths(int m, int n) {
        //1.确定dp数组以及下标i的含义
        //dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径
        //2.确定递推公式
        //想要求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]
        //dp[i][j]=dp[i][j-1]+dp[i-1][j];
        //3.dp数组的初始化
        //首先dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理
        int[][] dp=new int[m][n];
        for(int i=0;i<n;i++){
            dp[0][i]=1;
        }
        for(int j=0;j<m;j++){
            dp[j][0]=1;
        }
        //4.确定遍历顺序
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=dp[i][j-1]+dp[i-1][j];
                //System.out.println("i:"+i+",j:"+j+",res:"+dp[i][j]);
            }
        }
        //5.举例推导dp数组
         return dp[m-1][n-1];
    }
   
}

来分析一下时间复杂度,这个深搜的算法,其实就是要遍历整个二叉树。
这棵树的深度其实就是m+n-1(深度按从1开始计算)。
那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)
所以上面深搜代码的时间复杂度为O(2^(m + n - 1) - 1),可以看出,这是指数级别的时间复杂度,是非常大的。

class Solution {
   
    public int uniquePaths(int m, int n) {
        return dfs(m-1,n-1,m,n);
    }

    public int dfs(int i,int j,int m,int n){
        if(i<0 ||j <0){
            return 0;
        }
        //找到了一种路径
        if(i==0||j==0){
            return 1;
        }
        return dfs(i-1,j,m,n)+dfs(i,j-1,m,n);
    }
   
}

树递归的时间复杂度分析

这俩道题递归写法分析时间复杂度时是O(2n)和O(2(m + n - 1) - 1),斐波那契数 树深度是n,和最短路径 树深度是m+n-1 ,这个树深度是怎么理解得出的,有什么技巧嘛? 每次想不到,只能靠自己举例数下确实对上了,感觉没有理解到位。
:::tips
理解递归的时间复杂度O(n) O(logn):https://programmercarl.com/%E5%89%8D%E5%BA%8F/%E9%80%9A%E8%BF%87%E4%B8%80%E9%81%93%E9%9D%A2%E8%AF%95%E9%A2%98%E7%9B%AE%EF%BC%8C%E8%AE%B2%E4%B8%80%E8%AE%B2%E9%80%92%E5%BD%92%E7%AE%97%E6%B3%95%E7%9A%84%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6%EF%BC%81.html

理解树深度:
深度优先遍历(Depth First Search, 简称_DFS) 与广度优先遍历(Breath First Search)是图论中两种非常重要的算法_
树深度理解的话,每一步可选的动作方向可以看成一个树的分支,而具体的走一步是一个树的节点。在不同路径里,很显然的一条路径是直接右走再下走,这对应于树中的一个根到叶子的路径,这条路径的深度是 m+n-1。在所有的深搜中,也大致都可以这样类比,每一步搜索时可选的值是分支,每个选择是一个节点,一个能够到达递归终止条件的选择集合就是一条路径
:::

63. 不同路径 II

题目链接

https://leetcode.cn/problems/unique-paths-ii/description/

解题思路

跟上题差不都,就是多了些条件判断。
递推公式:
dp[i][j]=obstacleGrid[i][j]==1?0:(obstacleGrid[i-1][j]==1?0:dp[i-1][j])+(obstacleGrid[i][j-1]==1?0:dp[i][j-1]);
初始化要注意,遇到一个障碍物 后面都初始化为0

code

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m=obstacleGrid.length;
        int n=obstacleGrid[0].length;
        int[][] dp=new int[m][n];
        boolean falgm=false;
        boolean falgn=false;
        for(int i=0;i<m;i++){
            if(falgm || obstacleGrid[i][0]==1){
                dp[i][0]=0;
                falgm=true;
            }else{
                 dp[i][0]=1;
            }
           
        }
        for(int j=0;j<n;j++){
            if(falgn || obstacleGrid[0][j]==1){
                dp[0][j]=0;
                falgn=true;
            }else{
                dp[0][j]=1;
            }
            
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=obstacleGrid[i][j]==1?0:(obstacleGrid[i-1][j]==1?0:dp[i-1][j])+(obstacleGrid[i][j-1]==1?0:dp[i][j-1]);
                //System.out.println(dp[i][j]);
            }
        }
        return dp[m-1][n-1];
    }
}
  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值