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.hqwc.cn/news/312699.html

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

相关文章

arkts状态管理使用(@State、@Prop、@Link、@Provide、@Consume、@objectLink和@observed)

一、状态管理 1.在声明式UI中&#xff0c;是以状态驱动视图更新&#xff1a; ①状态&#xff08;State&#xff09;:指驱动视图更新的数据&#xff08;被装饰器标记的变量&#xff09; ②视图&#xff08;View&#xff09;:基于UI描述渲染得到用户界面 注意&#xff1a; ①…

【VB测绘程序设计】案例6——华氏温度与摄氏温度之间的转换程序(附源代码)

【VB测绘程序设计】案例6——华氏温度与摄氏温度之间的转换程序(附源代码) 文章目录 前言一、界面显示二、程序说明三、程序代码1程序变换2程序变换四、数据演示总结前言 本文主要掌握Val()函数以及String数据类型的应用,通过2个text来输入数据,2个Command控件来执行转换…

快速部署supervisord详解

Supervisor是一个用于监控和管理进程的工具。它可以在Unix-like系统中启动、停止、重启和管理后台进程&#xff0c;确保这些进程始终保持运行状态。 yum check-update 更新yum软件包索引 yum install epel-release -y 下载eprl源 yum install supervisor -y 直接yu…

【c语言】飞机大战2

1.优化边界问题 之前视频中当使用drawAlpha函数时&#xff0c;是为了去除飞机后面变透明&#xff0c;当时当飞机到达边界的时候&#xff0c;会出现异常退出&#xff0c;这是因为drawAlpha函数不稳定&#xff0c;昨天试过制作掩码图&#xff0c;下载了一个ps,改的话&#xff0c…

计算机基础面试题 |02.精选计算机基础面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

机器学习:贝叶斯估计在新闻分类任务中的应用

文章摘要 随着互联网的普及和发展&#xff0c;大量的新闻信息涌入我们的生活。然而&#xff0c;这些新闻信息的质量参差不齐&#xff0c;有些甚至包含虚假或误导性的内容。因此&#xff0c;对新闻进行有效的分类和筛选&#xff0c;以便用户能够快速获取真实、有价值的信息&…

虚拟专线网络(IP-VPN)

虚拟专线网络(IP-VPN)&#xff0c;因为它的安全性和可靠性。通过亚洲领先的 IP VPN 提供商。享受更高的可管理性和可扩展性&#xff0c;在多个站点之间交付 IP 流量或数据包&#xff0c;拥有亚太地区最大的 IP 骨干网。 1&#xff0c;保证正常运行时间&#xff0c;在网络链路发…

计算机视觉工程师就业前景如何

计算机视觉主要涵盖了图像处理、模式识别等多个领域&#xff0c;可以应用到很多行业中。随着人工智能技术的快速发展&#xff0c;计算机视觉作为其中的重要分支之一&#xff0c;其就业前景非常广阔。 为进一步贯彻落实中共中央印发《关于深化人才发展体制机制改革的意见》和国…

2023-12-14 LeetCode每日一题(用邮票贴满网格图)

2023-12-14每日一题 一、题目编号 2132. 用邮票贴满网格图二、题目链接 点击跳转到题目位置 三、题目描述 给你一个 m x n 的二进制矩阵 grid &#xff0c;每个格子要么为 0 &#xff08;空&#xff09;要么为 1 &#xff08;被占据&#xff09;。 给你邮票的尺寸为 stam…

易舟云财务软件使用教程【文章目录】

易舟云财务软件使用教程【文章目录】 1、财务软件导论2、易舟云财务软件3、财务软件原理4、账套5、会计凭证6、资金日记账7、发票8、员工工资9、固定资产10、期末处理(结转与结账)11、会计账簿12、财务报表13、财务软件设置 1、财务软件导论 财务软件导论 2、易舟云财务软件 …

CSS 纵向扩展动画

上干货 <template><!-- mouseenter"startAnimation" 表示在鼠标进入元素时触发 startAnimation 方法。mouseleave"stopAnimation" 表示在鼠标离开元素时触发 stopAnimation 方法。 --><!-- 容器元素 --><div class"container&q…

【C# 技术】 C# 常用排序方式——自定义数据排序

C# 常用排序方式——自定义数据排序 前言 在最近的项目中经常会对C#中的数据进行排序&#xff0c;对于基本数据类型&#xff0c;其排序方式比较简单&#xff0c;只需要调用内置算法即可实现&#xff0c;但对于自定义数据类型以及自定义排序规则的情况实现起来就比较麻烦&…