当前位置: 首页 > news >正文

LeetCode 二叉树 437. 路径总和 III

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
    • 解释
      和等于 22 的路径有 3 条。

题解

方法一:暴力枚举

根据题目,我们需要求出二叉树中一段路径的数字的和,判断是否 == targetSum

求一段数字的和可以用 前缀和 实现,避免重复枚举加和计算

先来看一段路径的情况,假设二叉树只有一条路径
那么此时问题可以转换为:求一给定数组中的连续子数组的和 == targetSum的个数
处理得到前缀和数组
之后枚举连续子数组的结尾,之后在遍历所有可能的开头,暴力寻找

那么对于有多条路径的二叉树
使用 vector<int> pre_sum记录下当前路径的前缀和数组
dfs 遍历二叉树
那么在遍历二叉树的过程中
每一个遇到的节点,都是一条路径中的一份子
那么意味着在 dfs 遍历树的过程中,其实就是遍历所有路径
所以遍历的过程,就是上述枚举连续子数组的结尾
于是对于每一个节点,遍历到它相当于将其作为结尾
接着枚举它的开头,也就是枚举前缀和数组vector<int> pre_sum,寻找到 target_Sum 即可

由于vector<int> pre_sum记录的当前路径的前缀和,当此节点递归完毕之后,需要对其进行回溯,防止影响其他路径


代码如下↓

class Solution {
public:int pathSum(TreeNode* root, int targetSum) {// 初始化前缀和数组,记录当前路径的累计和vector<int> pre_sum;// 当前路径的总和(使用long long防止溢出)long long sum=0;// 结果计数器,记录满足条件的路径数int res=0;// 定义DFS lambda函数(递归遍历二叉树)auto dfs = this auto&& dfs,TreeNode* p -> void {// 递归终止条件:当前节点为空时返回if(!p) {return ;}// 更新路径总和:将当前节点值加入累计和sum += p->val;// 将当前总和加入前缀和数组(记录路径历史)pre_sum.push_back(sum);// 检查路径和:从根节点到当前节点的总和是否等于targetSumif(sum == targetSum) {res += 1; // 满足条件则计数}// 枚举所有可能的路径开头(除当前节点自身)int n = pre_sum.size();for(int i = 0; i < n - 1; i++) {// 计算子路径和:从开头节点到当前节点的和(即sum - pre_sum[i])if(sum - pre_sum[i] == targetSum) {res += 1; // 满足条件则计数}}// 递归遍历左子树(深度优先)dfs(p->left);// 递归遍历右子树(深度优先)dfs(p->right);// 回溯:移除当前节点的贡献,确保不影响其他路径sum -= p->val;pre_sum.pop_back(); // 从前缀和数组中弹出当前总和};// 从根节点开始DFS遍历dfs(root);return res; // 返回最终结果}
};

枚举开头的时候,前缀和数组相减最多得到不包含开头的连续子数组,所以要么向前缀和数组开头插入 0 ,或对此时总和 sum 单独判断

并且由于 target_Sum 可以是 0 ,所以如果先更新的 pre_sum 数组,不能枚举到结尾,也就是路径不能是空的,空路径不能当做是总和 = 0


方法二:哈希表

对于一段结尾确定且为数组最后数据的连续子数组
相当于将数组分为了左右两部分
我们需要右边部分和为 target_Sum
那么左边部分和就为 数组总和sum - target_Sum

于是可以用哈希表hash_sum记录所有左边部分总和的值
对于每一个结尾,去查找哈希表中的个数即可
这样省去了枚举开头的过程


代码如下↓

class Solution {
public:int pathSum(TreeNode* root, int targetSum) {// 哈希表记录路径前缀和及其出现次数unordered_map<long long,int> hash_sum;// 初始化:空路径前缀和为0(处理子数组为整个数组的情况)hash_sum[0]=1;  long long sum=0;  // 当前递归路径的累计和int res=0;        // 满足条件的路径计数// DFS递归遍历二叉树(C++17显式this捕获lambda)auto dfs = this auto&& dfs,TreeNode* p -> void {if(!p) return;  // 空节点终止递归sum += p->val;  // 更新当前路径和// 关键步骤:先查询满足条件的子数组数量// 当前sum-targetSum表示需要的左侧部分和res += hash_sum[sum - targetSum];  // 后更新哈希表(避免包含空路径)hash_sum[sum] += 1;  // 递归遍历左右子树dfs(p->left);dfs(p->right);// 回溯:撤销当前节点的路径和记录hash_sum[sum] -= 1;  sum -= p->val;       // 恢复路径和};dfs(root);  // 从根节点启动DFSreturn res; // 返回目标路径总数}
};

和方法一中同样的问题,需要额外考虑子数组就是整个数组的情况,此时左边部分的总和就是0,所以哈希表 hash_sum[0]=1

依旧和方法一相同的问题,不存在空路径,所以不能先更新哈希表 hash_sum[sum]+=1,而是要先计算完满足条件的子数组后再更新

http://www.dtcms.com/a/553820.html

相关文章:

  • 【GoLang】【框架学习】【GORM】4. 使用 BeforeUpdate hook 操作时,出现反射报错
  • 有哪些好点的单页网站公司管理制度完整版
  • 庭田科技亮相成都复材盛会,以仿真技术赋能产业革新
  • 网站安全认证去哪做国内十大咨询公司排名
  • Maven高级-分模块设计与开发
  • markdown转为pdf导出
  • python - day 11
  • 污水处理厂三菱FX5U系列PLC通过Modbus TCP转CCLKIE工业智能网关和多个不同的仪表进行通讯案例
  • 东莞专业网站设计建站公司无锡网站推广优化费用
  • 海南网络公司网站建设wordpress 禁止收录
  • 哪里有学习做网站的html网站模板 免费
  • 网站中的表格phonegap下载
  • JAVA攻防-专题漏洞SPEL表达式SSTI模版Swagger接口Actuator泄露Spring特检
  • vue-day03
  • 高效稳定的命理测算平台:基于Linux+Nginx+PHP+MySQL的技术架构解析
  • 威海做网站哪家好西数网站助手
  • 企业商旅平台推荐:合思——全流程合规管控与生态协同标杆
  • 专业电商网站开发自己做图网站
  • 【flutter报错:Build failed due to use of deprecated Android v1 embedding.】
  • git 命令里的存档和检出的区别
  • 杰理芯片SDK-杰理SDK工程框架介绍
  • 家教中介网站怎么做学员引流用万网做网站
  • C# TaskCompletionSource.SetResult 用法详解
  • 网站建设模板html网站开发工程师岗位职责要求
  • 【Linux network和NetworkManager双网卡主备模式绑定】
  • SSO 单点登录
  • Linux 中如何查看系统的位数
  • 云南建设企业网站修改wordpress首页缩略图尺寸
  • 网站的投票系统怎么做wordpress文章类模板
  • AI智能体如何让用户洞察更简单、更快速、更精准