我们首先定义 rootSum(p,val) 表示以节点 p 为起点向下且满足路径总和为 val 的路径数目。我们对二叉树上每个节点 p 求出 rootSum(p,targetSum),然后对这些路径数目求和即为返回结果。
我们对节点 p 求 rootSum(p,targetSum) 时,以当前节点 p 为目标路径的起点递归向下进行搜索。假设当前的节点 p 的值为 val,我们对左子树和右子树进行递归搜索,对节点 p 的左孩子节点 pl 求出 rootSum(pl,targetSum−val),以及对右孩子节点 pr 求出 rootSum(pr,targetSum−val)。节点 p 的 rootSum(p,targetSum) 即等于 rootSum(pl,targetSum−val) 与 rootSum(pr,targetSum−val) 之和,同时我们还需要判断一下当前节点 p 的值是否刚好等于 targetSum。
我们采用递归遍历二叉树的每个节点 p,对节点 p 求 rootSum(p,val),然后将每个节点所有求的值进行相加求和返回。
int ret = 0; if (root->val == targetSum) { ret++; }
ret += rootSum(root->left, targetSum - root->val); ret += rootSum(root->right, targetSum - root->val); return ret; }
intpathSum(TreeNode* root, int targetSum){ if (!root) { return0; } int ret = rootSum(root, targetSum); ret += pathSum(root->left, targetSum); ret += pathSum(root->right, targetSum); return ret; } };
📊 复杂度分析
1、前缀和
时间复杂度:O(N),其中 N 是二叉树的节点数。深度优先搜索的递归确保了每个节点只会被遍历一次,且哈希表的查询和插入操作平均时间复杂度都是 O(1),所以整体时间复杂度是线性的。
空间复杂度:O(N),主要开销在于递归调用的系统栈空间(最坏情况下树退化为链表,深度为 N)以及哈希表占用的空间(最多存储 N 个不同的前缀和)。
2、暴力解法
时间复杂度:O(N2),其中 N 为该二叉树节点的个数。对于每一个节点,求以该节点为起点的路径数目时,则需要遍历以该节点为根节点的子树的所有节点,因此求该路径所花费的最大时间为 O(N),我们会对每个节点都求一次以该节点为起点的路径数目,因此时间复杂度为 O(N2)。