路径总和3是一道非常经典的遍历题变种:
给定一个二叉树的根节点 root ,和一个整数 targetSum ,
求该二叉树里节点值之和等于 targetSum 的 路径 的数目,而且路径 不需要从根节点开始,也不需要在叶子节点结束;
但是路径方向必须是向下的(只能从父节点到子节点)。
难点
取消了限制就需要考虑更多情况:每一个子树都可以分解为简单问题‘该子树是否存在路径满足targetSum’?
踩坑点
忽略数据范围
提示:
- 二叉树的节点个数的范围是
[0,1000]- <= Node.val <=
-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时:
- 优化:结束函数,后序的增减都不符合;
- 实际:后序路径的和为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;;
}
};