动态规划第二弹 基础提升

简介: 动态规划第二弹 基础提升

前言

在上一篇文章 动态规划从入门到LeetCode - 掘金 (juejin.cn) 中, 我们学习了怎么去做动态规划类的题目, 并进行了简单题目的练习

今日任务:

动态规划解题五部曲

  • 确定 dp 数组以及下标的含义
  • 确定递推公式
  • dp 数组如何初始化
  • 确认遍历顺序
  • 举例推导 dp 数组

62. 不同路径

题目描述

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

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

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

示例 1:

网络异常,图片无法展示
|

输入: m = 3, n = 7
输出: 28
复制代码

示例 2:

输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下
复制代码

示例 3:

输入: m = 7, n = 3
输出: 28
复制代码

示例 4:

输入: m = 3, n = 3
输出: 6
复制代码

 

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 109

思路分析

  1. 确定 dp 数组以及下标的含义:
    本题 机器人 处于 网格 中, 他有 两个 前进的方向, 那么本题就和上一篇文章做的 爬楼梯等题不一样了, dp 数组应该是 ==> dp[i][j] i代表 x轴 方向前进, j 代表 y轴 方向前进, dp[i][j] 代表到达该点的路径条数
  2. 确定递推公式
    由于本题有两种方向可选, 且到达的点位是固定可知的, 所以 dp[i][j] = dp[i-1][j] + dp[i][j-1]
  3. dp数组 如何初始化
  • 因为只能向下或者向右前进
  • 所以 dp[i][0] = 1;
  • 同理 dp[0][j] = 1;
  1. 确认遍历顺序
  • 因为只能向下或者向右前进
  • 所以直接从左向右遍历就可以了
  1. 举例推导 dp数组
  • 当 m = 3, n = 7时, 推导每个坐标值如下所示

网络异常,图片无法展示
|

代码展示

public int uniquePaths(int m, int n) {
    // 确定 dp 数组
    int[][] dp = new int[m][n];
    // 循环遍历数组
    for (int i = 0; i < m; i++) {
        for (int j = 0;j < n; j++) {
            // 初始化 dp 数组
            if (i == 0 || j == 0){
                dp[i][j] = 1;
                continue;
            }
            // 递推公式
            dp[i][j] = dp[i-1][j] + dp[i][j-1];
        }
    }
    // 返回 机器人 抵达右下角有多少种路径
    return dp[m-1][n-1];
}
复制代码

提交结果

网络异常,图片无法展示
|

63. 不同路径 II

题目描述

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

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

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 10 来表示。

示例 1:

网络异常,图片无法展示
|

输入: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出: 2
解释: 3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
复制代码

示例 2:

网络异常,图片无法展示
|

输入: obstacleGrid = [[0,1],[0,0]]
输出: 1
复制代码

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j]01

思路分析

首先获取网格 x,y 的长度, 然后创建新数组

  1. 确定dp数组以及下标的含义
    本题和上一题的区别就是多出了 障碍物, 那么 dp数组 的下标及其含义是不变的, 依旧是到达该点位的路径条数
  2. 确定递推公式
    一样的, dp[i][j] = dp[i-1][j] + dp[i][j-1]
  3. dp数组的初始化
  • 只能向下或者向右前进, 但是本题引入了 障碍物的情况, 所以初始化也要有相应的改变
  • 所以 dp[i][0] = obstacleGrid[i][0] == 0 ? 1 : 0;
  • 同理 dp[0][j] = obstacleGrid[i][0] == 0 ? 1 : 0;
  1. 确定遍历顺序
  • 和上一题一样的, 从左到右, 从上到下双层 for 循环进行遍历
  1. 举例推导这边就不举例了

代码展示

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    // 获取长度
    int x = obstacleGrid.length;
    int y = obstacleGrid[x - 1].length;
    // 判断边界, 起点和终点不能有障碍物
    if (obstacleGrid[0][0] == 1 || obstacleGrid[x - 1][y - 1] == 1){
        return 0;
    }
    // 创建 dp 数组
    int[][] dp = new int[x][y];
    // 初始化 dp 数组
    for (int i = 0; i < x && obstacleGrid[i][0] == 0; i++) {
        dp[i][0] = 1;
    }
    for (int i = 0; i < y && obstacleGrid[0][i] == 0; i++) {
        dp[0][i] = 1;
    }
    // 推导下标值
    for (int i = 1; i < x; i++) {
        for (int j = 1; j < y; j++) {
            // 如果有障碍物, 则赋予这个坐标为 0
            dp[i][j] = obstacleGrid[i][j] == 0 ? dp[i-1][j] + dp[i][j-1] : 0;
        }
    }
    return dp[x - 1][y - 1];
}
复制代码

提交结果

网络异常,图片无法展示
|

错误分析

第一次错误

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int length1 = obstacleGrid.length;
        int length = obstacleGrid[length1 - 1].length;
        for (int i = 0; i < length1; i++) {
            for (int j = 0; j < obstacleGrid[i].length; j++) {
                if (i == 0){
                    // 如果是障碍物就给他 0
                    if (obstacleGrid[i][j] == 1){
                        obstacleGrid[i][j] = 0;
                        break;
                    }
                    obstacleGrid[i][j] = 1;
                    continue;
                }else if (j == 0){
                    obstacleGrid[i][j] = obstacleGrid[i][j] == 0 ? 1 : 0;
                    continue;
                }
                obstacleGrid[i][j] = obstacleGrid[i][j] == 0 ? obstacleGrid[i-1][j] + obstacleGrid[i][j-1] : 0;
            }
        }
        return obstacleGrid[length1 - 1][length - 1];
    }
复制代码

网络异常,图片无法展示
|

入口放障碍也是没想到的, 下面是评论...

网络异常,图片无法展示
|

鉴于上述结果, 我在代码中新增了边界控制判断, 如果起点或者终点有障碍, 则直接返回 0, 新增判断代码如下, 然后就出现了第二次错误

if (obstacleGrid[0][0] == 1 || obstacleGrid[length1 - 1][length - 1] == 1){
    return 0;
}
复制代码

第二次错误

这是真的bug, 待我改一改

不得不说, 这个代码写的跟**屎山**一样, 多搞几个 for循环, 改一手吧, 不偷懒, 而是**新建一个 dp 数组来存储到达某个坐标点的路径数目**, 具体可看 代码提交 部分
复制代码

网络异常,图片无法展示
|

343. 整数拆分

题目描述

给定一个正整数 n ,将其拆分为 k正整数 的和( k >= 2 ),并使这些整数的乘积最大化。

返回 你可以获得的最大乘积

示例 1:

输入: n = 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
复制代码

示例 2:

输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
复制代码

提示:

  • 2 <= n <= 58

思路分析

  1. 确定 dp数组 以及下标的含义
    dp[i]: 第 i 个数的最大值
  2. 确定递推公式从 i 开始遍历, 遍历到 <= n, 然后 j 再从 1 开始遍历, 遍历到  j <= i-j, 也就是 j 最大值是 i-1, 有两种情况能够获取到 dp[i]
  • dp[i] = j*(i-j);    计算两个数相乘
  • dp[i] = j*dp[i-j];  计算两个及以上的数相乘 (dp[i-j] 是第 i-j 个数的最大值)
  1. dp数组的初始化
    默认 dp[2] = 1, dp[0] 和 dp[1]不用管, 因为 2<=n
  2. 确认遍历顺序
    从左往右开始遍历, i 从 3 开始, j 从 1开始遍历
for (int i = 3; i <= n; i++) {
    for (int j = 1; j <= i-j; j++) {
        // 递推公式
        dp[i] = Math.max(dp[i], Math.max((i-j)*j, dp[i-j]*j));
    }
}
复制代码
  1. 举例推导 pd数组

代码展示

public int integerBreak(int n) {
    // 创建 dp数组
    int[] dp = new int[n + 1];
    // 初始化 dp数组
    dp[2] = 1;
    for (int i = 3; i <= n; i++) {
        for (int j = 1; j <= i-j; j++) {
            // 递推公式
            dp[i] = Math.max(dp[i], Math.max((i-j)*j, dp[i-j]*j));
        }
    }
    return dp[n];
}
复制代码

提交结果

网络异常,图片无法展示
|

总结

经过这三道题的练习, 我对动态规划有了更深一步的理解, 真的就是循序渐进的学习, 奥利给



目录
相关文章
|
C++
第三大的数(C++)
第三大的数(C++)
215 0
|
项目管理
CMMI五大成熟度定义及过程管理类详解
CMMI五大成熟度定义及过程管理类详解
935 0
|
SQL 关系型数据库 MySQL
【MySQL】数据库约束与聚合查询和联合查询等进阶操作知识汇总(下)
【MySQL】数据库约束与聚合查询和联合查询等进阶操作知识汇总(下)
504 0
|
2天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
4865 6
|
14天前
|
人工智能
千问办公官网入口:阿里AI办公QwenWork产品页和免费网页端链接
千问办公官网含两大入口:一是网页端(qwenwork.cn),即开即用,支持浏览器直接访问;二是阿里云产品页 https://t.aliyun.com/U/JNKJuO 提供免费/付费版详情、功能介绍及使用指南。
|
14天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
|
13天前
|
IDE 开发工具
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
Qoder国际版上线全新内置大模型Sonus(/ˈsoʊnəs/),全球领先,专精超长任务执行与电脑操作(Computer Use)。配合Qoder桌面端0.2.3版本,可自主完成编程、金融建模、科研及表格制作等复杂工作。现全面支持Qoder全系产品,效率提升3.2倍。
1684 8
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
|
15天前
|
缓存 人工智能 自然语言处理
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
本文是阿里云百炼平台Qwen3.8-Flash大模型的选型接入指南,作为兼顾性能与响应速度的高性价比多模态模型,它支持百万级上下文窗口、全场景多模态输入与完整智能体能力矩阵,适配编程辅助、智能体协作等核心场景。文中同步梳理了最新下调的阶梯定价、夜间4折等优惠活动,搭配OpenAI兼容流式调用示例,帮助开发者低成本快速落地高并发AI应用。
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
|
9天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1004 1