给定一个二叉树的根节点 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
cpp
/**
* 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 pathSum(TreeNode* root, int targetSum) {
int ans = 0;
unordered_map<long long, int> cnt = {{0,1}};
auto dfs = [&](auto && dfs, TreeNode *node, long long s){
if(node == nullptr){
return;
}
s += node -> val;
ans += cnt.contains(s - targetSum) ? cnt[s - targetSum] : 0;
cnt[s]++;
dfs(dfs, node->left, s);
dfs(dfs, node->right, s);
cnt[s]--;
};
dfs(dfs, root, 0);
return ans;
}
};
前缀+哈希的前置知识(力扣560和力扣930),然后加入了树的运算。
cpp
auto dfs = [&](auto && dfs, TreeNode *node, long long s){
if(node == nullptr){
允许 lambda 表达式访问并修改其外部作用域的所有变量。比如 ans 和 cnt 都是在 lambda 表达式之外定义的,通过 [&] 捕获,lambda 可以直接对它们进行操作。
cpp
s += node -> val;
s是前缀和。
cpp
ans += cnt.contains(s - targetSum) ? cnt[s - targetSum] : 0;
ans用来统计和为targetSum的个数。
cpp
cnt[s]++;
记录当前节点的前缀和在哈希表中数目+1,供接下来的运算。
cpp
dfs(dfs, node->left, s);
dfs(dfs, node->right, s);
按深度优先搜索遍历树。
cpp
cnt[s]--;
恢复现场,这一步很重要,例如当运算完左子树返回到父节点的时候,要开始运算右子树,由于左子树和右子树在计算路径的时候并没有关联,所以需要恢复左子树前缀和对应在哈希表中的数量,避免影响计算右子树路径和为targetSum的数量。