LeetCode二叉树路径和专题:最大路径和与路径总和计数的策略

目录

437. 路径总和 III

深度优先遍历

前缀和优化

124. 二叉树中的最大路径和 


437. 路径总和 III

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)

示例 1:

输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。

示例 2:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3

提示:

  • 二叉树的节点个数的范围是 [0,1000]
  • -109 <= Node.val <= 109 
  • -1000 <= targetSum <= 1000 

深度优先遍历

遍历每个节点,以每个节点为根节点统计所有路径和为targetSum情况

class Solution {public int pathSum(TreeNode root, int targetSum) {if (root == null) {return 0;}int ret = rootSum(root, targetSum);ret += pathSum(root.left, targetSum);ret += pathSum(root.right, targetSum);return ret;}public int rootSum(TreeNode root, int targetSum) {int ret = 0;if (root == null) {return 0;}int val = root.val;if (val == targetSum) {ret++;} ret += rootSum(root.left, targetSum - val);ret += rootSum(root.right, targetSum - val);return ret;}
}

前缀和优化

解法一中应该存在许多重复计算,我们现在定义:前缀和是一个数列的每一项索引从0开始,表示从第0项到当前项的和。在这个问题中,我们将前缀和应用于二叉树的路径上,即从根节点到当前节点的所有节点值的和。

  1. 初始化:创建一个哈希表 prefix 来保存前缀和及其出现次数。为了处理从根节点开始的路径,我们提前在哈希表中设置前缀和0的计数为1。

  2. 递归遍历:使用深度优先搜索遍历二叉树。在每个节点处,计算从根节点到当前节点的前缀和。

  3. 查找当前路径和:检查当前的前缀和减去 targetSum 的结果是否在之前的路径中已经出现过,也就是检查 curr - targetSum 是否在哈希表 prefix 中。如果是,说明存在一个子路径的和等于 targetSum,将对应的次数添加到结果中。

  4. 更新哈希表:在访问节点之前,将当前前缀和的计数增加1,以表示这个前缀和现在被包含在路径中。

  5. 递归子节点:继续对左右子节点进行相同的处理。

  6. 回溯:在返回之前,需要将当前节点的前缀和的计数减1,因为当前节点即将被回溯,不应该计入其他路径(不存在以某个节点为根节点左右子树都存在的路径,所以要回溯避免影响其他路径)

class Solution {// 主函数public int pathSum(TreeNode root, int targetSum) {// 哈希表用于存储所有前缀和及其出现次数Map<Long, Integer> prefix = new HashMap<Long, Integer>();// 初始化:前缀和为0的路径有1条(空路径)prefix.put(0L, 1);// 开始深度优先搜索return dfs(root, prefix, 0, targetSum);}// 辅助函数:深度优先搜索public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) {// 如果当前节点为空,则返回0,表示没有路径if (root == null) {return 0;}int ret = 0; // 用于记录路径数curr += root.val; // 更新当前路径和// 查找当前路径和减去目标值的结果是否在前缀和中出现过// 出现过则表示找到了一条路径ret = prefix.getOrDefault(curr - targetSum, 0);// 更新前缀和中当前路径和的计数prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);// 递归地搜索左子树和右子树,并累加路径数ret += dfs(root.left, prefix, curr, targetSum);ret += dfs(root.right, prefix, curr, targetSum);// 回溯:在返回之前,将当前节点的路径和的计数减1// 因为当前节点即将被回溯,不应该计入其他路径prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);// 返回找到的路径总数return ret;}
}

让我们通过一个具体的例子来说明回溯在前缀和算法中的应用。假设有以下二叉树:

        10
       /  \
      5   -3
     / \    \
    3   2   11
   / \   \
  3  -2   1

并且我们要找的 targetSum 是8。我们将按照前缀和算法遍历这棵树。

  1. 开始于根节点 (10):

    • 当前前缀和: curr = 10
    • prefix = { (0,1) } (初始化,路径和为0出现了1次)
  2. 移动到左子节点 (5):

    • 当前前缀和: curr = 15
    • 更新前缀和计数: prefix = { (0,1), (15,1) }
  3. 继续到该节点的左子节点 (3):

    • 当前前缀和: curr = 18
    • 更新前缀和计数: prefix = { (0,1), (15,1), (18,1) }
  4. 进一步到该节点的左子节点 (3):

    • 当前前缀和: curr = 21
    • 更新前缀和计数: prefix = { (0,1), (15,1), (18,1), (21,1) }
  5. 回溯到节点 (3) 父节点 (3):

    • 我们完成了节点 (3) 的所有子节点的遍历
    • 当前前缀和: curr = 18
    • 回溯prefix = { (0,1), (15,1), (18,1) },移除之前节点 (3) 的前缀和
  6. 遍历节点 (3) 的右子节点 (-2):

    • 当前前缀和: curr = 16
    • 更新前缀和计数: prefix = { (0,1), (15,1), (18,1), (16,1) }
    • 回溯prefix = { (0,1), (15,1), (18,1) },完成节点 (-2) 的遍历,移除它的前缀和
  7. 回溯到节点 (5) 并转向它的右子节点 (2):

    • 我们完成了节点 (5) 的左子树的遍历
    • 当前前缀和: curr = 15
    • 回溯prefix = { (0,1), (15,1) },移除之前节点 (3) 和 (-2) 的前缀和
    • 当前前缀和: curr = 17 (添加节点 (2))
    • 更新前缀和计数: prefix = { (0,1), (15,1), (17,1) }
    • 检查17 (当前前缀和) - 8 (targetSum) = 9,在 prefix 中没有 9,所以没有发现新路径
    • 遍历节点 (2) 的左子节点 (1)
    • 当前前缀和: curr = 18 (添加节点 (1))
    • 更新前缀和计数: prefix = { (0,1), (15,1), (17,1), (18,1) }
    • 检查18 (当前前缀和) - 8 (targetSum) = 10,在 prefix 中有 10(根节点的值),所以我们找到了一条路径: 10 → 5 → 2 → 1
    • 回溯:完成节点 (1) 的遍历,回溯节点 (2)
  8. 最终回溯到根节点 (10) 并转向它的右子节点 (-3):

    • 当前前缀和: curr = 10
    • 回溯prefix = { (0,1) },移除左子树的前

124. 二叉树中的最大路径和 

二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

示例 1:

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:

  • 树中节点数目范围是 [1, 3 * 104]
  • -1000 <= Node.val <= 1000
class Solution {int maxSum = Integer.MIN_VALUE;public int maxPathSum(TreeNode root) {maxGain(root);return maxSum;}public int maxGain(TreeNode node) {if (node == null) {return 0;}// 递归计算左右子节点的最大贡献值// 只有在最大贡献值大于 0 时,才会选取对应子节点int leftGain = Math.max(maxGain(node.left), 0);int rightGain = Math.max(maxGain(node.right), 0);// 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值int priceNewpath = node.val + leftGain + rightGain;// 更新答案maxSum = Math.max(maxSum, priceNewpath);// 返回节点的最大贡献值return node.val + Math.max(leftGain, rightGain);}
}

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

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

相关文章

简单FTP客户端软件开发——VMware安装Linux虚拟机(命令行版)

VMware安装包和Linux系统镜像&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1UwF4DT8hNXp_cV0NpSfTww?pwdxnoh 提取码&#xff1a;xnoh 这个学期做计网课程设计【简单FTP客户端软件开发】需要在Linux上配置 ftp服务器&#xff0c;故此用VMware安装了Linux虚拟机&…

burpsuite模块介绍之compare

导语 Burp Comparer是Burp Suite中的一个工具&#xff0c;主要提供一个可视化的差异比对功能&#xff0c;可以用于分析比较两次数据之间的区别。它的应用场景包括但不限于&#xff1a; 枚举用户名过程中&#xff0c;对比分析登陆成功和失败时&#xff0c;服务器端反馈结果的区…

编程式导航传参

(通过js代码实现跳转) 按照path进行跳转 第一步&#xff1a; 在app.vue中(前提是规则已经配置好) <template><div id"app">App组件<button clicklogin>跳转</button><!--路由出口-将来匹配的组件渲染地方--><router-view>&l…

【嵌入式学习笔记-01】什么是UC,操作系统历史介绍,计算机系统分层,环境变量(PATH),错误

【嵌入式学习笔记】什么是UC&#xff0c;操作系统历史介绍&#xff0c;计算机系统分层&#xff0c;环境变量&#xff08;PATH&#xff09;&#xff0c;错误 文章目录 什么是UC?计算机系统分层什么是操作系统&#xff1f; 环境变量什么是环境变量&#xff1f;环境变量的添加&am…

简写英语单词

题目&#xff1a; 思路&#xff1a; 这段代码的主要思路是读取一个字符串&#xff0c;然后将其中每个单词的首字母大写输出。具体来说&#xff0c;程序首先使用 fgets 函数读取一个字符串&#xff0c;然后遍历该字符串中的每个字符。当程序遇到一个字母时&#xff0c;如果此时…

基于图论的图像分割 python + PyQt5

数据结构大作业&#xff0c;基于图论中的最小生成树的图像分割。一个很古老的算法&#xff0c;精度远远不如深度学习算法&#xff0c;但是对于代码能力是一个很好的锻炼。 课设要求&#xff1a; &#xff08; 1 &#xff09;输入&#xff1a;图像&#xff08;例如教室场景图&a…

47、激活函数 - sigmoid

今天在看一个比较常见的激活函数,叫作 sigmoid 激活函数,它的数学表达式为: 其中,x 为输入,画出图来看更直观一些。 Sigmoid 函数的图像看起来像一个 S 形曲线,我们先分析一下这个函数的特点。 Sigmoid 函数的输出范围在 (0, 1) 之间,并且不等于0或1。 Sigmoid 很明显是…

Codeforces Round 900 (Div. 3)(A-F)

比赛链接 : Dashboard - Codeforces Round 900 (Div. 3) - Codeforces A. How Much Does Daytona Cost? 题面 : 思路 : 在序列中只要找到k&#xff0c;就返回true ; 代码 : #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)…

spring 之 事务

1、JdbcTemplate Spring 框架对 JDBC 进行封装&#xff0c;使用 JdbcTemplate 方便实现对数据库操作 1.1 准备工作 ①搭建子模块 搭建子模块&#xff1a;spring-jdbc-tx ②加入依赖 <dependencies><!--spring jdbc Spring 持久化层支持jar包--><dependency&…

性能优化(CPU优化技术)-ARM Neon详细介绍

本文主要介绍ARM Neon技术&#xff0c;包括SIMD技术、SIMT、ARM Neon的指令、寄存器、意图为读者提供对ARM Neon的一个整体理解。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09…

2024年总结的前端学习路线分享(学习导读)

勤学如春起之苗&#xff0c;不见其增&#xff0c;日有所长 。辍学如磨刀之石&#xff0c;不见其损&#xff0c;日有所亏。 在写上一篇 2023年前端学习路线 的时候&#xff0c;时间还在2023年初停留&#xff0c;而如今不知不觉时间已经悄然来到了2024年&#xff0c;回顾往昔岁月…

三、Mysql安全性操作[用户创建、权限分配]

一、用户 1.创建用户 CREATE USER test1localhost identified BY test1;2.删除用户 DROP USER test2localhost;二、权限分配 1.查询用户权限 SHOW GRANTS FOR test1localhost;2.分配权限 # 分配用户所有权限在for_end_test库的test1表 GRANT ALL PRIVILEGES ON for_end_t…

Pycharm引用其他文件夹的py

Pycharm引用其他文件夹的py 方式1&#xff1a;包名设置为Sources ROOT 起包名的时候&#xff0c;需要在该文件夹上&#xff1a;右键 --> Mark Directory as --> Sources ROOT 标记目录为源码目录&#xff0c;就可以了。 再引用就可以了 import common from aoeweb impo…

OCP NVME SSD规范解读-3.NVMe管理命令-part2

NVMe-AD-8&#xff1a;在某些情况下&#xff08;如Sanitize命令、Format NVM命令或TCG Revert方法后数据被清除&#xff09;&#xff0c;设备应允许读取已清除的LBAs而不产生错误&#xff0c;并在最后一次清除完成后&#xff0c;对未写入LBAs的读取返回所有零值给主机 NVMe-AD…

鸿蒙开发之android对比开发《基础知识》

基于华为鸿蒙未来可能不再兼容android应用&#xff0c;推出鸿蒙开发系列文档&#xff0c;帮助android开发人员快速上手鸿蒙应用开发。 1. 鸿蒙使用什么基础语言开发&#xff1f; ArkTS是鸿蒙生态的应用开发语言。它在保持TypeScript&#xff08;简称TS&#xff09;基本语法风…

二叉树题目:根到叶路径上的不足结点

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;根到叶路径上的不足结点 出处&#xff1a;1080. 根到叶路径上的不足结点 难度 6 级 题目描述 要求 给定二叉树的根结点 root \texttt{root} root…

关键字:throw关键字

在 Java 中&#xff0c;throw关键字用于抛出异常。当程序执行过程中发生意外情况&#xff0c;如错误的输入、资源不足、错误的逻辑等&#xff0c;导致程序无法正常执行下去时&#xff0c;可以使用throw关键字抛出异常。 以下是使用throw关键字的一些示例&#xff1a; 抛出异常…

服装店收银系统不只是收银 还需要线上商城和线上批发

一个综合性的服装店收银系统可以结合线上商城和线上批发功能&#xff0c;提供以下特点和优势&#xff1a; 线上商城&#xff1a;将服装店的商品信息同步到线上商城平台&#xff0c;让顾客可以通过网站或移动应用程序浏览和购买商品。线上商城可以实现在线支付、订单跟踪、售后服…

MySQL数据库索引优化

一、引言 1. 索引的重要性 MySQL数据库索引的重要性主要体现在&#xff0c;一是查询速度优化&#xff0c;索引可以极大地提高查询速度。对于没有索引的表&#xff0c;MySQL必须进行全部扫描来找到所需的行&#xff0c;如果表中数据量很大&#xff0c;那么通常很慢。通过适当的…

大数据规模存储的几个核心问题

文章目录 三个关键问题RAID&#xff08;独立磁盘冗余阵列&#xff09;RAID是如何解决关于存储的三个关键问题&#xff1f;水平伸缩 大规模数据存储都需要解决几个核心问题&#xff0c;这些问题都是什么呢&#xff1f; 三个关键问题 1.数据存储容量的问题 既然大数据要解决的…