算法练习-踩坑历数‘路径总和3’

81 阅读2分钟

路径总和3是一道非常经典的遍历题变种:

给定一个二叉树的根节点 root ,和一个整数 targetSum ,

求该二叉树里节点值之和等于 targetSum 的 路径 的数目,而且路径 不需要从根节点开始,也不需要在叶子节点结束;

但是路径方向必须是向下的(只能从父节点到子节点)。

难点

取消了限制就需要考虑更多情况:每一个子树都可以分解为简单问题‘该子树是否存在路径满足targetSum’?

踩坑点

忽略数据范围

提示:

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

leetcode 提供的函数接口,targetSum是int,符合数据范围,但是当targetSum - Node.Val,就可能存在溢出的情况,比如用例:targetSum - Node.val时就溢出了

[715827882,715827882,null,715827882,null,1,null,715827882,null,715827882,null,715827882,null]
targetSum = -3

过早的优化

当一段路径满足taregtSum时:

  1. 优化:结束函数,后序的增减都不符合;
  2. 实际:后序路径的和为0! 例如用例:
[1,-2,-3,1,3,-2,null,-1]

总结

累加子问题判断符合targetSum的路径,代码如下:

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:

   int count;
   // 唯一的约束是自上而下,每个节点都要开始算其与子树能否满足目标树
   void checking(TreeNode *root, long targetSum) {
       if (!root) { return; }
       if ( root->val == targetSum ) { count++; }
       
       if (root->left) { checking(root->left,  targetSum - root->val); }
       if (root->right){ checking(root->right, targetSum - root->val); }
   }
   void tracing(TreeNode* root, long targetSum) {
       if (!root) { return ; } // 搜索到头
       // 计算当前节点出发到子树构成的序列能否满足
       checking(root, targetSum);
       if (root->left) { tracing(root->left,  targetSum); } 
       if (root->right){ tracing(root->right, targetSum); }
   }

   int pathSum(TreeNode* root, int targetSum) {
       count = 0;
       tracing(root, targetSum);
       int result = 0;
       return count;;
   }
};