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

news2024/9/20 22:39:07

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.coloradmin.cn/o/1870270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android Kotlin 中的闭包函数

闭包函数是现代编程语言中一个重要的概念&#xff0c;Kotlin 作为一种现代的 JVM 语言&#xff0c;自然也支持闭包函数。本文将详细介绍闭包函数的概念、在Kotlin 中的使用方法&#xff0c;以及一些常见的应用场景。 什么是闭包函数&#xff1f; 闭包函数&#xff0c;也称为闭…

50etf期权合约一手多少钱你知道吗?

今天带你了解50etf期权合约一手多少钱你知道吗&#xff1f;50etf期权有不同价值的合约&#xff0c;每手50etf期权合约从几元到几百元再到上千元的都有&#xff0c;具体需要根据投资者选择了什么价值的合约。 50etf期权权利金 50ETF期权合约的权利金是买方需要缴纳的费用&…

上古世纪战争台服官网地址+台服预约+预创建角色教程

上古世纪战争台服上线啦&#xff0c;在《上古世纪战争》中&#xff0c;通过主要势力和地区&#xff0c;剧情和角色可以想起原作。《上古世纪战争》的主要背景为&#xff0c;原大陆消失之后&#xff0c;完成移民的种族们定居在诺伊大陆之后遇到的多个势力之间的冲突。同时&#…

视觉灵感的探索和分享平台

做设计没灵感&#xff1f;大脑一片空白&#xff1f;灵感是创作的源泉&#xff0c;也是作品的灵魂所在。工作中缺少灵感&#xff0c;这是每个设计师都会经历的苦恼&#xff0c;那当我们灵感匮乏的时候&#xff0c;该怎么办呢&#xff1f;别急&#xff0c;即时设计、SurfCG、Lapa…

ulimit报错

问题 执行命令“ulimit -c 2048 ”时报错&#xff1a;“bash: ulimit: core file size: cannot modify limit: Operation not permitted” 原因 权限不够。 解决办法 执行命令“sudo gedit /etc/security/limits.conf”打开文件limits.conf文件内添加内容如下&#xff1a;…

Dataease配置Nginx代理

Dataease配置Nginx代理 一.修改前端静态资源地址和后端接口地址 **1.**修改应用程序的上下文路径 配置文件地址&#xff1a;backend/src/main/resources 找到文件application-whole.properties&#xff0c;做如下修改&#xff1a; **2.**修改前端静态资源路径和打包配置 配…

Linux创建目录——mkdir命令,du命令,touch用法,创建tree拓扑图

1. mkdir 命令 格式 mkdir - 参数 路径 / 目录名 参数 -p &#xff1a;快速创建多级目录&#xff08;递归目录&#xff09; -v &#xff1a;显示创建目录的详细过程 例&#xff1a; [rootserver ~] # mkdir t1 [rootserver ~] # mkdir t2 t3 t4 [rootserver ~] # mk…

[数据集][目标检测]电缆钢丝绳线缆缺陷检测数据集VOC+YOLO格式1800张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1800 标注数量(xml文件个数)&#xff1a;1800 标注数量(txt文件个数)&#xff1a;1800 标注…

Python学习打卡:day17

day17 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day17121、Python 操作 MySQL 基础使用pymysql创建到 MySQL 的数据库链接执行 SQL 语句执行非查询性质的SQL语句执行查询性质的SQL语句 122、Pyth…

Python实践项目讲解:如何用制作一个桌面宠物

制作一个桌面宠物&#xff08;Desktop Pet&#xff09;在Python中通常涉及多个步骤&#xff0c;包括创建宠物的图形界面、添加动画效果、处理用户交互等。下面是一个简化的步骤指南&#xff0c;帮助你开始使用Python制作桌面宠物&#xff1a; 选择图形库&#xff1a; Tkinter&…

音视频开发30 FFmpeg 视频编码- 流程以及重要API,H264编码原理说明,该章节使用h264编码说明

一.H264编码原理 1 视频为什么需要进行编码压缩 ◼ 一张为 720x480 的图像&#xff0c;用 YUV420P 的格式来表示&#xff0c;其大小为&#xff1a; 720*480*1.5 约等于 0.5MB 。 ◼ 如果是 25 帧&#xff0c; 10 分钟的数据量 0.5M*10*60*25 7500MB -> 7GB 多 ◼ …

SQL注入漏洞—SQL注入简介与原理

一、SQL注入基础 1.1 什么是SQL注入漏洞 SQL注入漏洞从1998年圣诞节大火以来长盛不衰&#xff0c;虽然开发人员想出各种方法对他进行围追堵截&#xff0c;却始终无法将其赶尽杀绝&#xff0c;SQL注入的根本原因就是将SQL代码插入或添加到应用&#xff08;用户&#xff09;的输…

Facebook之梦:数字社交的无限可能

在当今数字化和全球化的时代&#xff0c;社交网络已经成为人们日常生活不可或缺的一部分。作为全球最大的社交平台之一&#xff0c;Facebook不仅连接了数十亿用户&#xff0c;还深刻影响了我们的社交方式、文化交流和信息传播。然而&#xff0c;Facebook所代表的不仅仅是一个网…

Python湍流隐式模型耗散粘性方程和大涡流模拟

&#x1f3af;要点 &#x1f3af;达朗贝尔一维波动通解&#xff0c;二维变速模拟 | &#x1f3af;达朗贝尔算子解双曲波形微分方程 | &#x1f3af;耗散系统粘性伯格斯方程快速傅里叶变换算法 | &#x1f3af;二维线性和非线性对流扩散解和湍流隐式建模 &#x1f4dc;偏微分方…

MMCV【mmclassification】 从0到1 之 Docker 容器环境搭建步骤总结

🥇 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 🎉 声明: 作为全网 AI 领域 干货最多的博主之一,❤️ 不负光阴不负卿 ❤️ 文章目录 📙 Linux 下 Docker 安装环境检查Docker 安装 [ root 或者 sudo 权限用户可安装 ]给 普通用户 加入 Docker …

非最大值抑制(NMS)函数

非最大值抑制&#xff08;NMS&#xff09;函数 flyfish 非最大值抑制&#xff08;Non-Maximum Suppression, NMS&#xff09;是计算机视觉中常用的一种后处理技术&#xff0c;主要用于目标检测任务。其作用是从一组可能存在大量重叠的候选边界框中&#xff0c;筛选出最具代表…

软件必须要进行跨浏览器测试吗?包括哪些内容和注意事项?

随着互联网的普及和发展&#xff0c;用户对软件的要求越来越高。无论是在台式机、笔记本还是移动设备上&#xff0c;用户都希望能够以最好的体验来使用软件。然而&#xff0c;不同的浏览器在解析网页的方式、支持的技术标准等方面存在差异&#xff0c;这就导致了同一个网页在不…

LeetCode 585, 438, 98

目录 585. 2016年的投资题目链接表要求知识点思路代码 438. 找到字符串中所有字母异位词题目链接标签思路代码 98. 验证二叉搜索树题目链接标签合法区间思路代码 中序遍历思路代码 585. 2016年的投资 题目链接 585. 2016年的投资 表 表Insurance的字段为pid、tiv_2015、tiv…

RabbitMQ WEB管理端介绍

页面功能概览 Overview(概述)Connections(连接)Channels(通道)Exchanges(交换器)Queues(队列)Admin(用户管理)。 1. Overview(概述) 主要分为三部分 1.1 Queued messages&#xff08;所有队列的消息情况&#xff09; Ready&#xff1a;待消费的消息总数Unacked&#xff1a;待应…

抖音集成:通过MessageBox引领数字化营销新潮流

抖音集成&#xff1a;通过MessageBox引领数字化营销新潮流 在数字化营销的大潮中&#xff0c;企业需要不断探索新的方式来优化其营销策略&#xff0c;以抓住更多的市场机会。抖音作为一款全球知名的短视频社交平台&#xff0c;凭借其庞大的用户群体和高度互动的特性&#xff0…