leetcode 链接:求和路径
《程序员面试代码指南》by 左程云 中相似题目:★★☆☆在二叉树中找到累加和为指定值的最长路径长度
题目
给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。
示例:
给定如下二叉树,以及目标和 sum = 22,
5/ \4 8/ / \11 13 4/ \ / \7 2 5 1
返回:
3
解释:和为 22 的路径有:[5,4,11,2], [5,8,4,5], [4,11,7]
解答
方法一:
参考:《程序员面试代码指南》by 左程云 中相似题目:★★☆☆在二叉树中找到累加和为指定值的最长路径长度
- 初始:
- 建立一个哈希表 
sumMap,存储<sum, cnt>键值对,sum 代表从根节点到某个节点的和,cnt 代表从根节点到后续节点和为 sum 的节点数(也就是从根结点出发得到和为 sum 的节点数)- 初始存入 
(0,1) 
 - 初始存入 
 preSum代表从根节点到上一个节点(当前节点的父节点)的和,初始设为 0pathCnt代表和为目标值的路径数,即答案,初始设为 0
 - 建立一个哈希表 
 递归,前序遍历
void preOrder(TreeNode* root, int preSum, int targetSum, int& pathCnt, unordered_map<int, int> sumMap)- 递归结束条件:
root为空,返回
 - 将 
preSum和root的值相加,得到从二叉树根节点到当前节点root的和curSum - 在哈希表中查找 
curSum - targetSum- 如果存在,则将路径数 + 哈希表中其对应的键值
 
 - 如果哈希表中存在 
curSum,则将其键值 + 1;否则插入(curSum, 1) - 递归左子树
 - 递归右子树
 回溯:将刚才在哈希表中增加的 curSum 键值 -1,变回原样,如果减为 0 ,删掉该记录
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { private: void preOrder(TreeNode* root, int preSum, int targetSum, int& pathCnt, unordered_map<int, int> sumMap) { if(root == NULL) return; int curSum = preSum + root->val; if(sumMap.find(curSum - targetSum) != sumMap.end()) pathCnt += sumMap[curSum-targetSum]; if(sumMap.find(curSum) == sumMap.end()) sumMap.insert(make_pair(curSum, 1)); else sumMap[curSum] += 1; preOrder(root->left, curSum, targetSum, pathCnt, sumMap); preOrder(root->right, curSum, targetSum, pathCnt, sumMap); sumMap[curSum] -= 1; if(sumMap[curSum] == 0) sumMap.erase(curSum); } public: int pathSum(TreeNode* root, int sum) { unordered_map<int, int> sumMap; sumMap.insert(make_pair(0, 1)); int preSum = 0; int pathCnt = 0; preOrder(root, preSum, sum, pathCnt, sumMap); return pathCnt; } };执行结果: ``` 执行结果:通过
- 递归结束条件:
 
执行用时:460 ms, 在所有 C++ 提交中击败了 5.55% 的用户 内存消耗:96.3 MB, 在所有 C++ 提交中击败了 5.10% 的用户
<a name="MKriF"></a>
## 方法二:
先调用 `void preOrder(TreeNode* root, int sum, int& pathCnt)` 这个函数深度优先遍历二叉树的每个节点:
- 递归结束条件,如果当前节点为空,则返回
- 调用 `calPathCnt(TreeNode* root, int target, int& pathCnt)` 计算以当前节点为根节点的子树中路径和为 `sum` 的路径数
- 递归遍历左子树
- 递归遍历右子树
```cpp
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
private:
    void calPathCnt(TreeNode* root, int target, int& pathCnt)
    {
        if(root == NULL)
            return;
        target -= root->val;    // target 是从根节点走到当前节点的这条路径上,目标 sum 减去这条路径上各结点的值的差
        if(target == 0)    // 如果 target 减为 0,说明这条路径的节点值和为目标 sum
            ++pathCnt;    // 路径数 +1
        calPathCnt(root->left, target, pathCnt);
        calPathCnt(root->right, target, pathCnt);
    }
    void preOrder(TreeNode* root, int sum, int& pathCnt)
    {
        if(root == NULL)
            return;
        calPathCnt(root, sum, pathCnt);
        preOrder(root->left, sum, pathCnt);
        preOrder(root->right, sum, pathCnt);
    }
public:
    int pathSum(TreeNode* root, int sum) {
        int pathCnt = 0;
        preOrder(root, sum, pathCnt);
        return pathCnt;
    }
};
执行结果:
执行结果:通过
执行用时:20 ms, 在所有 C++ 提交中击败了 41.17% 的用户
内存消耗:18.6 MB, 在所有 C++ 提交中击败了 74.76% 的用户
                    