力扣热门算法题 112. 路径总和,115. 不同的子序列,120. 三角形最小路径和

news/2024/4/28 2:54:06/文章来源:https://blog.csdn.net/qq_52213943/article/details/137033604

 112. 路径总和,115. 不同的子序列,120. 三角形最小路径和,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.25 可通过leetcode所有测试用例。

目录

112. 路径总和

解题思路

完整代码

Java

Python

115. 不同的子序列

解题思路

完整代码

Java

Python

120. 三角形最小路径和

解题思路

完整代码

Java

Python


112. 路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

解题思路

为了解决这个问题,我们可以采用递归的方法来判断二叉树中是否存在一条从根节点到叶子节点的路径,其路径上所有节点值相加等于目标和 targetSum。这个方法的关键在于递归地减少 targetSum,直到到达叶子节点时,检查剩余的 targetSum 是否等于叶子节点的值。具体步骤如下:

  1. 基础情况:如果当前节点为 null,则返回 false,因为我们已经到达了叶子节点的下一个位置,而没有找到符合条件的路径。
  2. 叶子节点判断:如果当前节点是叶子节点(即没有左右子节点),检查 targetSum 是否等于当前节点的值。如果等于,则找到了一条符合条件的路径,返回 true
  3. 递归查找:如果当前节点不是叶子节点,递归地在左右子树中查找是否存在符合条件的路径。将 targetSum 减去当前节点的值,并传给左右子节点进行递归。
  4. 返回结果:如果左子树或右子树的递归调用返回 true,则存在符合条件的路径,返回 true;否则,返回 false

完整代码

Java
/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {if (root == null) {return false;}// 如果是叶子节点,检查剩余的 targetSum 是否等于叶子节点的值if (root.left == null && root.right == null) {return root.val == targetSum;}// 递归地检查左右子树return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);}
}
Python
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:# 基础情况:如果当前节点为空,返回 Falseif not root:return False# 叶子节点检查:如果是叶子节点,检查 targetSum 是否等于叶子节点的值if not root.left and not root.right:return root.val == targetSum# 递归检查:递归检查左右子树,减去当前节点的值更新 targetSumleft_has_path = self.hasPathSum(root.left, targetSum - root.val)right_has_path = self.hasPathSum(root.right, targetSum - root.val)# 如果左右子树中任一满足条件,返回 Truereturn left_has_path or right_has_path

115. 不同的子序列

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 10^9 + 7 取模。

示例 1:

输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit
rabbbit
rabbbit
示例 2:

输入:s = "babgbag", t = "bag"
输出:5
解释:
如下所示, 有 5 种可以从 s 中得到 "bag" 的方案。 
babgbag
babgbag
babgbag
babgbag
babgbag

解题思路

我们可以定义一个二维的DP数组 dp[i][j],其中 dp[i][j] 表示 s 的前 i 个字符中 t 的前 j 个字符作为子序列出现的次数。我们需要计算 dp[len(s)][len(t)] 的值,即整个 st 作为子序列出现的次数。

  1. 初始化

    • j 为 0,即 t 为空字符串时,空字符串是任何字符串的子序列,所以 dp[i][0] = 10 <= i <= len(s))。
    • i 为 0,即 s 为空字符串时,除了 t 也为空字符串的情况外,s 中不可能包含非空 t 作为子序列,所以 dp[0][j] = 01 <= j <= len(t))。
  2. 状态转移

    • 如果 s[i - 1] == t[j - 1],那么 dp[i][j] 可以从 dp[i - 1][j - 1]s 的前 i - 1 个字符中 t 的前 j - 1 个字符作为子序列出现的次数)转移过来,加上 dp[i - 1][j](即使 s[i - 1] 匹配上了 t[j - 1],我们也可以选择不使用 s[i - 1] 这个字符)。
    • 如果 s[i - 1] != t[j - 1],那么 dp[i][j] 只能从 dp[i - 1][j] 转移过来,因为 s[i - 1] 不能作为匹配 t[j - 1] 的字符。
  3. 结果dp[len(s)][len(t)] 即为最终结果。

完整代码

Java
class Solution {public int numDistinct(String s, String t) {int m = s.length(), n = t.length();int[][] dp = new int[m + 1][n + 1];// 初始化,当 t 为空字符串时,空字符串是任何字符串的子序列for (int i = 0; i <= m; i++) {dp[i][0] = 1;}// 动态规划填表for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (s.charAt(i - 1) == t.charAt(j - 1)) {dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];} else {dp[i][j] = dp[i - 1][j];}}}// 结果取模return dp[m][n] % (1000000007);}}
Python
class Solution:def numDistinct(self, s: str, t: str) -> int:m, n = len(s), len(t)dp = [[0] * (n + 1) for _ in range(m + 1)]# 初始化,当 t 为空字符串时,空字符串是任何字符串的子序列for i in range(m + 1):dp[i][0] = 1# 动态规划填表for i in range(1, m + 1):for j in range(1, n + 1):if s[i - 1] == t[j - 1]:dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]else:dp[i][j] = dp[i - 1][j]# 结果取模return dp[m][n] % (10**9 + 7)

120. 三角形最小路径和

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

示例 1:

输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:23 46 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

示例 2:

输入:triangle = [[-10]]
输出:-10

解题思路

解决这个问题,我们可以采用自底向上的动态规划方法,这样可以避免处理边界条件,使问题变得更简单。思路如下:

  1. 初始化:创建一个与三角形最后一行大小相同的DP数组(或直接在输入的三角形上进行操作以节省空间),用于存储到达每个位置的最小路径和。
  2. 自底向上计算:从三角形的倒数第二行开始,逐行向上计算每个位置的最小路径和。每个位置的最小路径和可以通过其正下方和右下方的两个位置的最小路径和加上当前位置的值得到。
  3. 转移方程:设dp[i][j]表示到达三角形第ij列位置的最小路径和,则dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j]
  4. 结果:经过自底向上的计算后,三角形顶部的元素(即dp[0][0])即为整个三角形的最小路径和。

完整代码

Java
class Solution {public int minimumTotal(List<List<Integer>> triangle) {int n = triangle.size();int[] dp = new int[n];List<Integer> lastRow = triangle.get(n - 1);// 初始化dp数组为三角形的最后一行for (int i = 0; i < n; i++) {dp[i] = lastRow.get(i);}// 自底向上逐行计算最小路径和for (int i = n - 2; i >= 0; i--) {  // 从倒数第二行开始向上for (int j = 0; j <= i; j++) {  // 遍历当前行的每个元素// 更新当前位置的最小路径和dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j);}}return dp[0];  // 返回三角形顶部的最小路径和}}
Python
class Solution:def minimumTotal(self, triangle: List[List[int]]) -> int:n = len(triangle)dp = triangle[-1]  # 初始化dp数组为三角形的最后一行# 自底向上逐行计算最小路径和for i in range(n - 2, -1, -1):  # 从倒数第二行开始向上for j in range(len(triangle[i])):  # 遍历当前行的每个元素# 更新当前位置的最小路径和dp[j] = min(dp[j], dp[j + 1]) + triangle[i][j]return dp[0]  # 返回三角形顶部的最小路径和

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

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

相关文章

机器学习——元学习

元学习&#xff08;Meta Learning&#xff09;是一种机器学习方法&#xff0c;旨在使模型能够学习如何学习。它涉及到在学习过程中自动化地学习和优化学习算法或模型的能力。元学习的目标是使模型能够从有限的训练样本中快速适应新任务或新环境。 在传统的机器学习中&#xff…

数据结构算法系列----贪心算法

目录 一、什么是贪心 1、定义&#xff1a; 2、举例&#xff1a; 二、例题 完整代码&#xff1a; 一、什么是贪心 1、定义&#xff1a; 贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法。在贪心算法中&#xff0c;通过 局部最优 解来达到全局最优解。贪心算法…

Mysql数据库:事务管理

目录 一、Mysql事务的概述 1、Mysql事务的概念 2、事务的ACID四大特性 3、事务之间的相互影响 4、事务的四种隔离级别 5、MySQL与Oracle自动提交事务的区别 6、事务隔离级别的作用范围 二、Mysql事务相关操作 1、查询和设置事务隔离级别 1.1 全局级事务隔离级别 1.1…

量子计算+运营优化!IonQ 和 德国DESY 合作提升机场登机口调度效率

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 编辑丨慕一 编译/排版丨 沛贤 深度好文&#xff1a;1200字丨8分钟阅读 3月14日&#xff0c;量子计算公司IonQ宣布了与德国电子同步加速器&#xff08;DESY&#xff0c;德国的大型粒子物理学研…

【正点原子FreeRTOS学习笔记】————(2)FreeRTOS的任务创建和删除

这里写目录标题 一、任务创建和删除的API函数&#xff08;熟悉&#xff09;二、任务创建和删除&#xff08;动态方法&#xff09;&#xff08;掌握&#xff09;三、任务创建和删除&#xff08;静态方法&#xff09;&#xff08;掌握&#xff09; 一、任务创建和删除的API函数&a…

数据结构:初识树和二叉树

目前主流的方式是左孩子右兄弟表示法 我们的文件系统就是一个树 以上就是树的概念&#xff0c;我们今天还要来学习一种从树演变的重要的结构&#xff1a;二叉树 顾名思义二叉树就是一个结点最多有两个子树。 其中我们还要了解满二叉树和完全二叉树的概念 注意我们的完全二叉…

Java项目:78 springboot学生宿舍管理系统的设计与开发

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色&#xff1a;管理员、宿管、学生 管理员管理宿管员&#xff0c;管理学生&#xff0c;修改密码&#xff0c;维护个人信息。 宿管员管理公寓…

微服务高级篇(三):分布式缓存+Redis集群

文章目录 一、单点Redis的问题及解决方案二、Redis持久化2.1 单机安装Redis2.2 RDB持久化2.3 AOF持久化2.4 RDB和AOF对比 三、Redis主从3.1 搭建Redis主从架构3.1.1 集群结构3.1.2 准备实例和配置3.1.3 启动3.1.4 开启主从关系3.1.5 测试 3.2 数据同步3.2.1 全量同步【建立连接…

盏燕生物科技将出席2024第七届燕窝天然滋补品博览会

参展企业介绍 深圳市盏燕生物科技有限公司&#xff0c;办公室地址位于中国第一个经济特区&#xff0c;鹏城深圳&#xff0c;深圳市龙岗区平湖街道禾花社区富安大道18号亚钢工贸大楼1栋1017A&#xff0c;我公司主要提供一般经营项目是&#xff1a;初级农产品、海产品、化妆品、…

批量添加时,两个选择框为一组,不能选择一模一样的值,将不符合条件的值禁止设为禁止点击

效果展示&#xff1a; 完整代码如下&#xff1a; <template><div class"container"><div v-for"item in arr"><el-select v-model"item.name" placeholder"请选择" change"changeBox"><el-opti…

el-card设置内边距

el-card设置内边距 :deep(.el-card .el-card__body) {padding: 5px; }

Spring中常用的注解及使用规则

文章目录 前言一、Spring注解是什么&#xff1f;二、使用步骤1.注解使用 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 在学习Spring中&#xff0c;我们汇经常用到注解来简化我们的工作&#xff0c;接下来将为大家简单介绍一下常用的注解 提示&a…

如何实现无公网IP及服务器实现公网环境企业微信网页应用开发调试

文章目录 1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 企业微信开发者在应用的开发测试阶段&#xff0c;应用服务通常是部署在开发环境&#xff0c;在有数据回调的开发场…

蓝桥杯真题Day40 倒计时19天 纯练题!

蓝桥杯第十三届省赛真题-统计子矩阵 题目描述 给定一个 N M 的矩阵 A&#xff0c;请你统计有多少个子矩阵 (最小 1 1&#xff0c;最大 N M) 满足子矩阵中所有数的和不超过给定的整数 K? 输入格式 第一行包含三个整数 N, M 和 K. 之后 N 行每行包含 M 个整数&#xf…

java日志技术——Logback日志框架安装及概述

前言&#xff1a; 整理下学习笔记&#xff0c;打好基础&#xff0c;daydayup!!! 日志 什么是日志 程序中的日志&#xff0c;通常就是一个文件&#xff0c;里面记录的是程序运行过程中的各种信息&#xff0c;通过日志可以进行操作分析&#xff0c;bug定位等 记录日志的方案 程…

【爬虫基础】第6讲 opener的使用

在爬虫中&#xff0c;opener是一个用来发送HTTP请求的对象。它可以用来模拟浏览器发送请求&#xff0c;包括设置请求头、处理Cookie等操作。使用opener可以实现一些高级功能&#xff0c;如模拟登录、处理验证码等。 方法1&#xff1a; from urllib.request import Request,bu…

【数据结构】顺序表的实现——静态分配

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;数据结构 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

Linux manim安装

简介 根据文档可知, manim目前分为两个版本, 一个是由3Blue1Brown维护更新的最新版本的manimgl, 另一个是稳定的社区版本manim or manimce. 两个版本在安装和使用上都有些不同, 不要搞混. Linux manim ERROR No package ‘pangocairo’ found Getting requirements to buil…

使用 .NET 和 Teams Toolkit 构建 AI 机器人、扩展 Copilot for Microsoft 365 以及更多

作者&#xff1a;Ayca Bas 排版&#xff1a;Alan Wang Teams Toolkit for Visual Studio 帮助 .NET 开发人员为 Microsoft Teams 构建、调试和发布应用程序。我们很高兴向大家宣布&#xff0c;Teams Toolkit for Visual Studio 2022 17.9 版本为 .NET 开发人员提供了许多令人兴…

【Qt】使用Qt实现Web服务器(六):QtWebApp用户名密码登录

1、示例 1)演示 2)登录 3)显示 2、源码 示例源码Demo1->LoginController void LoginController::service(HttpRequest& request, HttpResponse& response) {