代码随想录算法训练营第三十六天|62.不同路径、 63. 不同路径 II、343.整数拆分(可跳过)、96.不同的二叉搜索树(可跳过)

62.不同路径

在这里插入图片描述

题目链接:62.不同路径
文档讲解:代码随想录
状态:还行

思路:当前状态的只有可能是从上面或者左边过来的,所以 dp[i][j] = dp[i-1] + dp[j-1]

题解:

    public int uniquePaths(int m, int n) {
        if (m == 1 && n == 1) {
            return 1;
        }
        int[][] dp = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i == 0 || j == 0) {
                    dp[i][j] = 1;
                } else {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m - 1][n - 1];
    }

63. 不同路径 II

在这里插入图片描述

题目链接:63. 不同路径 II
文档讲解:代码随想录
状态:还行

思路:
对于第一行中的元素(不包括第一个元素),路径数量只取决于左边格子的路径数量。
对于第一列中的元素(不包括第一个元素),路径数量只取决于上边格子的路径数量。
对于其他位置,路径数量为上边和左边格子的路径数量之和。
如果当前位置有障碍物,则将该位置的路径数量设为0。

题解:

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    // 如果起点本身有障碍物,返回 0,因为无法出发
    if (obstacleGrid[0][0] == 1) {
        return 0;
    }

    int m = obstacleGrid.length;  // 获取网格的行数
    int n = obstacleGrid[0].length;  // 获取网格的列数
    int[][] dp = new int[m][n];  // 创建一个二维数组 dp 用于存储每个位置的路径数量

    dp[0][0] = 1;  // 起点位置的路径数量设为 1

    // 遍历网格
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            // 如果在第一行,且不是第一个元素
            if (i == 0 && j > 0) {
                dp[i][j] = dp[i][j - 1];  // 只能从左边的格子过来
            }
            // 如果在第一列,且不是第一个元素
            if (j == 0 && i > 0) {
                dp[i][j] = dp[i - 1][j];  // 只能从上边的格子过来
            }
            // 对于其他位置
            if (i > 0 && j > 0) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];  // 路径数量为从上边和左边格子的路径数量之和
            }
            // 如果当前格子有障碍物,路径数量为 0
            if (obstacleGrid[i][j] == 1) {
                dp[i][j] = 0;
            }
        }
    }

    // 返回终点位置的路径数量
    return dp[m - 1][n - 1];
}

343.整数拆分

在这里插入图片描述

题目链接:343.整数拆分
文档讲解:代码随想录
状态:不会

思路:

dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。从1遍历j,然后有两种渠道得到dp[i]
第一种是j * (i - j) 直接相乘。
第二种是j * dp[i - j]。这里的dp[i-j] 表示将 i-j 进一步拆分后得到的最大乘积,这个拆分过程中有递归的影子,所以第二种方式就是一堆数字相乘最后能得到的最大值。

题解:

    public int integerBreak(int n) {
        // dp[i] 表示将正整数 i 拆分成至少两个正整数的和后,这些正整数的乘积的最大值。
        int[] dp = new int[n + 1];
        dp[2] = 1;
        /*遍历计算:从 i=3 开始遍历到 i=10,对每个 i 进行如下计算:
        当 i=3 时,j 可以取 1 或 2,分别计算 j*(3-j) 和 j*dp[3-j],取最大值,得到 dp[3] = 2。
        当 i=4 时,j 可以取 1、2 或 3,分别计算 j*(4-j) 和 j*dp[4-j],取最大值,得到 dp[4] = 4。
        当 i=5 时,j 可以取 1、2、3 或 4,分别计算 j*(5-j) 和 j*dp[5-j],取最大值,得到 dp[5] = 6。
        当 i=6 时,j 可以取 1、2、3、4 或 5,分别计算 j*(6-j) 和 j*dp[6-j],取最大值,得到 dp[6] = 9。
        当 i=7 时,j 可以取 1、2、3、4、5 或 6,分别计算 j*(7-j) 和 j*dp[7-j],取最大值,得到 dp[7] = 12。
        当 i=8 时,j 可以取 1、2、3、4、5、6 或 7,分别计算 j*(8-j) 和 j*dp[8-j],取最大值,得到 dp[8] = 18。
        当 i=9 时,j 可以取 1、2、3、4、5、6、7 或 8,分别计算 j*(9-j) 和 j*dp[9-j],取最大值,得到 dp[9] = 27。
        当 i=10 时,j 可以取 1、2、3、4、5、6、7、8 或 9,分别计算 j*(10-j) 和 j*dp[10-j],取最大值,得到 dp[10] = 36。*/
        for (int i = 3; i <= n; i++) {
            for (int j = 1; j <= i - j; j++) {
//                max(j * (i-j), j * dp[i-j]):这部分是关键,它考虑了两种情况:
//                j * (i-j):将整数 i 拆分为两个数,即 j 和 i-j,它们的乘积为 j * (i-j)。
//                j * dp[i-j]:将整数 i 拆分成 j 和若干个数之和,其中至少一个数大于 1。dp[i-j] 表示将 i-j 进一步拆分后得到的最大乘积,因此乘积为 j * dp[i-j]。
//                max(dp[i], ...):这部分确保我们每次更新 dp[i] 时,取最大的乘积。
//                因为我们要求的是整体的最大乘积,所以要比较当前计算出的乘积与之前已经计算过的 dp[i] 的值,取其中较大的那个作为 dp[i] 的值。也就是j取不同值时算到的各个dp[i]中取最大的
                dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
            }
        }
        return dp[n];
    }

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

题目链接:96.不同的二叉搜索树
文档讲解:代码随想录
状态:不会

数学思路:
卡特兰数的简单应用,递推通项公式都可以简单求解。
通项公式: f ( n ) = 1 n + 1 C 2 n n f(n) = \frac{1}{n+1} C_{2n}^{n} f(n)=n+11C2nn

递推公式: f ( n ) = ∑ k = 1 n f ( n − k ) f ( k − 1 ) = ( 2 n ) ! ( n + 1 ) ! n ! f(n) = \sum_{k=1}^{n} f(n-k) f(k-1) = \frac{(2n)!}{(n+1)!n!} f(n)=k=1nf(nk)f(k1)=(n+1)!n!(2n)!

通过这道题可以非常简单的得到递推公式:

  1. 选数字k作为二叉排序树的根节点
  2. 小于k的数字(1, 2, …, k-1)构成左子树,左子树一共有 f ( k − 1 ) f(k-1) f(k1) 种可能
  3. 大于k的数字 (k+1, …, n)构成右子树,右子树一共有 f ( n − k ) f(n-k) f(nk)种可能
  4. 选k作为根节点一共有 f ( n − k ) f ( k − 1 ) f(n-k) f(k-1) f(nk)f(k1) 种可能
  5. 一共有n个数字可以作为根节点,故一共 f ( n ) = ∑ k = 1 n f ( n − k ) f ( k − 1 ) f(n) = \sum_{k=1}^{n} f(n-k) f(k-1) f(n)=k=1nf(nk)f(k1)种可能

dp思路:

  1. 目标:计算节点数量为 i 时的二叉搜索树数量 dp[i]。
  2. 遍历根节点:对于每个可能的根节点值 j,其中 j 的取值范围是从 1 到 i。这表示我们考虑将每个节点作为根节点,来构建二叉搜索树。
  3. 左子树和右子树:当我们选择节点 j 作为根节点时,左子树包含节点值从 1 到 j-1 的所有节点,右子树包含节点值从 j+1 到 i 的所有节点。
  4. 状态转移:对于每个根节点 j,其左子树的节点数量为 j-1,右子树的节点数量为 i-j。因此,以节点 j 为根的二叉搜索树数量为 dp[j - 1] * dp[i - j]。
  5. 累加更新:将所有可能的以节点 j 为根的二叉搜索树数量累加到 dp[i] 上,即 dp[i] += dp[j - 1] * dp[i - j];。这样可以计算出节点数量为 i 时的所有可能的二叉搜索树数量。
  6. 结果:最终,dp[i] 的值即为节点数量为 i 时的二叉搜索树数量。

数学题解:

    //数学方法
    public int numTrees(int n) {
        // 计算组合数 C(2n, n)
        long C = binomialCoeff(2 * n, n);
        // 返回 Catalan 数 C_n = C / (n + 1)
        return (int) (C / (n + 1));
    }

    // 计算二项式系数 C(n, k)
    private long binomialCoeff(int n, int k) {
        long res = 1;
        // C(n, k) = C(n, n - k), 提高效率
        if (k > n - k) {
            k = n - k;
        }
        // 计算 C(n, k)
        for (int i = 0; i < k; ++i) {
            res *= (n - i);
            res /= (i + 1);
        }
        return res;

    }

dp题解:

  public int numTrees(int n) {
        // 创建一个数组用于存储不同节点数量对应的二叉搜索树数量
        int[] dp = new int[n + 1];
        // 初始化,当节点数量为 0 或 1 时,只有一种情况,即空树或只有一个节点的树
        dp[0] = 1;
        dp[1] = 1;
        // 计算不同节点数量对应的二叉搜索树数量
        // 变量 i 表示当前正在计算的节点数量
        for (int i = 2; i <= n; i++) {
            // 变量 j 表示当前正在考虑作为根节点的值,
            // 因为是BST,左子树包含了从 1 到 j-1 的节点,右子树包含了从 j+1 到 i 的节点
            for (int j = 1; j <= i; j++) {//头结点从1开始遍历,遍历到结点i
                // 将每个数作为根节点,计算其左右子树的 BST 数量,
                // 然后将左右子树的数量相乘,累加得到以当前数为根节点的 BST 数量
                // 但是为了求当前i节点为根节点的数量,还要把2到i的节点数量加起来
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        // 返回 n 个节点的 BST 数量
        return dp[n];
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/750369.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

入职必备-mac下载安装maven

1、Maven 下载 1.1、官网下载安装包 官网下载链接 历史版本下载&#xff1a; Index of /dist/maven/maven-3/3.8.8/binaries 注意 .bash_profile 文件中的符号可能会影响配置 1.2、解压文件 2、Maven 环境配置 2.1、Java JDK 依赖 配置 maven 环境变量需要先配置好 JDK …

Knife4j 2.2.X 版本 swagger彻底禁用

官方文档配置权限&#xff1a;https://doc.xiaominfo.com/v2/documentation/accessControl.html#_3-5-1-%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E5%B1%8F%E8%94%BD%E8%B5%84%E6%BA%90 通常有时候我们碰到的问题如下&#xff1a; 在开发Knife4j功能时,同很多开发者经常讨论的问…

检索增强生成RAG系列2--提高RAG准确度的关键点

上一章讲到了RAG的基本流程&#xff0c;但是如果只是完成一个基本流程&#xff0c;想要在商业上使用还是不行&#xff0c;因为正常商业上的使用其准确度至少有个90%甚至更高。那么如何提高RAG的准确度&#xff0c;那么需要看看RAG有哪些关键点。 目录 1 RAG结构图2 文档处理3 …

群晖系统百度网盘套件卸载之后无法再次安装 ContainerManager项目无法删除

前言 最近重新组了个NAS&#xff0c;在套件迁移的时候遇到个头疼的问题。在用矿神的百度网盘在迁移的时候出错了&#xff0c;于是我自己删掉baiduapp得容器和镜像然后卸载套件。不知道中间出了啥问题&#xff0c;套件是已经卸载了&#xff0c;但是群晖ContainerManager套件中的…

企业有必要安装数据文件加密软件吗?哇!这么多好处

需要的 一、查看以下分析&#xff0c;便能得出结论 安全防护提升&#xff1a;禁止拷贝、打印、截屏等&#xff0c;还能够设置文件的浏览次数、有效期&#xff0c;提供多层次的文档保护措施。 核心机密保护&#xff1a;企业的核心机密文件、技术资料、客户资料等重要信息是公…

RabbitMQ安装部署

简介 RabbitMQ一款知名的开源消息队列系统&#xff0c;为企业提供消息的发布、订阅、点对点传输等消息服务。 RabbitMQ在企业开发中十分常见&#xff0c;课程为大家演示快速搭建RabbitMQ环境。 安装 rabbitmq在yum仓库中的版本比较老&#xff0c;所以我们需要手动构建yum仓库…

学习分享-Redis 中的压缩列表 (Ziplist)

Redis 中的压缩列表 (Ziplist) 压缩列表 (Ziplist) 是 Redis 内部用于优化小规模数据存储的一种紧凑数据结构。它设计用于高效地存储包含少量元素的列表、哈希表或有序集合&#xff0c;以减少内存占用和提高性能。以下是压缩列表的详细介绍&#xff1a; 1. 压缩列表的结构 压…

mac 安装mysql启动报错 ERROR!The server quit without update PID file

发现问题&#xff1a; mac安装mysql初次启动报错&#xff1a; 一般出现这种问题&#xff0c;大多是文件夹权限&#xff0c;或者以前安装mysql卸载不干净导致。首先需要先确定问题出在哪&#xff1f;根据提示我们可以打开mysql的启动目录&#xff0c;查看启动日志。 问题解决&a…

逆变器使用手册:类型详解、安装要点与维护须知

逆变器随着可再生能源的兴起和移动电源需求的激增已成为连接直流电与交流电世界的桥梁&#xff0c;其重要性不言而喻。无论是太阳能发电系统的高效利用&#xff0c;还是汽车、游艇等移动设备的电力供应&#xff0c;逆变器都扮演着关键角色。然而&#xff0c;正确的使用方法是确…

Linux运维:MySQL数据库(1)

1.信息与数据&#xff1a; 数据是信息的载体&#xff0c;信息是数据的内涵。数据库就是存储数据的仓库&#xff0c;并长期存储在计算机磁盘中&#xff0c;可由多个用户和应用程序共享的数据集合&#xff0c;就是数据库。 2.数据库中的数据的特点&#xff1a; 2.1.数据是按照某…

ai assistant 是所有编程助手中最出色的一款 ?

ai assistant激活成功后&#xff0c;如图 ai assistant渠道&#xff1a;https://web.52shizhan.cn/activity/ai-assistant 在去年五月份的 Google I/O 2023 上&#xff0c;Google 为 Android Studio 推出了 Studio Bot 功能&#xff0c;使用了谷歌编码基础模型 Codey,Codey 是…

element-plus 日期选择添加确定按钮

需求&#xff1a;选择日期后&#xff0c;点击确定按钮关闭面板 思路&#xff1a; 使用shortcuts自定义确定和取消按钮选择日期后使用handleOpen()强制开启面板点击确定后使用handleClose()关闭面板 <template><el-date-pickerref"pickerRef"v-model"…

【Linux】对共享库加载问题的深入理解——基本原理概述

原理概述 【linux】详解——库-CSDN博客 共享库被加载后&#xff0c;系统会为该共享库创建一个结构&#xff0c;这个结构体中的字段描述了库的各种属性。在内存中可能会加载很多库&#xff0c;每一个库都用一个结构体描述。把这些结构体用一些数据结构管理起来&#xff0c;系…

盲盒小程序:线上盲盒发展机遇

盲盒已经成为了当下年轻人的潮玩首选方式。随着二次元、影视行业的快速发展&#xff0c;给盲盒提供了各种新的发展方向&#xff0c;盲盒商品也在不断创新&#xff0c;种类丰富多样。玩家在拆盲盒时随机获得某一商品&#xff0c;具有惊喜感和刺激性。 目前&#xff0c;随着小程…

深入剖析Tomcat(十、十一) 详解StandardWrapper

《深入剖析Tomcat》第十章介绍了Tomcat的安全机制&#xff0c;主要就是对servlet的访问做安全验证&#xff0c;如果Tomcat中设置了某些servlet需要指定角色的用户才能访问&#xff0c;则需要客户端进行登录验证&#xff0c;如果用户名密码正确并且该用户拥有该角色的话&#xf…

Vite 动态导入警告问题解决方案

如上图我要实现从后台获取权限菜单并动态导入进行渲染 但由于 vite 暂时不支持这种导入方式 图中也给出了提示 本人也是这么去做了 但并没什么卵用 后来参考了 vite 的 import.meta.glob 这种方式 我在处理菜单权限控制的菜单里进行了如下操作&#xff1a; …

数据转换 | Matlab基于R对称点模式(symmetric dot pattern, SDP)一维序列信号转二维时频图象

目录 效果分析基本介绍程序设计参考资料获取方式 效果分析 基本介绍 数据转换 | Matlab基于R对称点模式(symmetric dot pattern, SDP)一维序列信号转二维时频图象 SDP常被用于信号分析和深度学习模式识别。 SDP是一种基于极坐标系的图像表示方法&#xff0c;可以直接将原始信…

版本控制工具-git的基本使用

目录 前言一、git简介二、git工作流程三、安装git并配置git3.1 配置用户名和邮箱3.2 配置.gitignore文件&#xff08;可选&#xff09;3.3 配置ssh key&#xff08;可选&#xff09; 四、git基本命令4.1 创建本地仓库4.2 将工作区内容提交到本地仓库4.3 将本地仓库内容推送到远…

【例子】webpack 开发一个可以加载 markdown 文件的加载器 loader 案例

Loader 作为 Webpack 的核心机制&#xff0c;内部的工作原理却非常简单。接下来我们一起来开发一个自己的 Loader&#xff0c;通过这个开发过程再来深入了解 Loader 的工作原理。 这里我的需求是开发一个可以加载 markdown 文件的加载器&#xff0c;以便可以在代码中直接导入 m…

nacos漏洞汇总

1 nacos介绍 1.1 nacos是啥 Alibaba Nacos是阿里巴巴推出来的一个新开源项目&#xff0c;是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。致力于帮助发现、配置和管理微服务。Nacos提供了一组简单易用的特性集&#xff0c;可以快速实现动态服务发现、服…
最新文章