题目描述:
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例 1:
方法一:
/**
* 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 ans = 0;
//vector<vector<int>> ans2;
//void dfs(TreeNode* cur, int targetSum, int states, vector<int> states2)
void dfs(TreeNode* cur, int targetSum, int states)
{
if (cur == nullptr) return;
states += cur->val;
//states2.push_back(cur->val);
if (states == targetSum)
{
ans++;
//ans2.push_back(states2);
}
//dfs(cur->left, targetSum, states, states2);
dfs(cur->left, targetSum, states);
//dfs(cur->right, targetSum, states, states2);
dfs(cur->right, targetSum, states);
states -= cur->val;
//states2.pop_back();
}
void recur(TreeNode* cur,int targetSum)
{
if (cur == nullptr) return;
vector<int> states2 = {};
//dfs(cur, targetSum, 0, states2);
dfs(cur, targetSum, 0);
recur(cur->left, targetSum);
recur(cur->right, targetSum);
}
int pathSum(TreeNode* root, int targetSum) {
recur(root, targetSum);
//for (int i = 0; i < ans2.size(); i++)
//{
// for (int j = 0; j < ans2[i].size(); j++)
// {
// cout << ans2[i][j] << " ";
// }cout << endl;
//}
return ans;
}
};
经典题目,就这样简单的暴力解法却总是做不出来,今天拿出来解决了吧。代码中的注释部分为存储每一条符合的路径。
在以下段中,我习惯性的把if语句放在了states += cur->val 之前,但是这样会导致在后续遍历cur的左右子树时,会将同一条路径重复判断两次。
states += cur->val;
//states2.push_back(cur->val);
if (states == targetSum)
{
ans++;
//ans2.push_back(states2);
}
方法二:
class Solution {
public:
int ans = 0;
void recur(TreeNode* cur, int targetSum,int curpresum, unordered_map<int, int>& mappresum)
{
if (cur == nullptr) return;
curpresum += cur->val;
if (mappresum.count(curpresum - targetSum))
{
ans += mappresum[curpresum - targetSum];
}
mappresum[curpresum]++;
recur(cur->left, targetSum, curpresum, mappresum);
recur(cur->right, targetSum, curpresum, mappresum);
mappresum[curpresum]--;
curpresum -= cur->val;
}
int pathSum(TreeNode* root, int targetSum) {
unordered_map<int, int> mappresum;
mappresum[0]++;
int curpresum = 0;
recur(root, targetSum, curpresum, mappresum);
return ans;
}
};
使用前缀和,每次遍历时,记录下从根节点到该节点cur的前缀和curpresum,然后在哈希表中查找是否存在某个节点的前缀和为curpresum - targetsum,如果有说明这个节点到cur的路径之和就是targetsum。
由于可能存在某条路径的起始位置是根节点,导致curpresume == targetsum,所以在递归之前就要往哈希表中添加0这个数字。
注意我在写的过程中有个问题,在下方的代码中,我原先将 mappresum[curpresum]++; 放在了if语句之前,但这样会导致先往哈希表中添加了curpresum这个数字,如果targetSum是0的话,就会错误多计算一条路径。
另外,我一开始将 ans += mappresum[curpresum - targetSum]; 写成了ans++,但是满足前缀和为curpresum - targetSum的可能有多种情况。
curpresum += cur->val;
if (mappresum.count(curpresum - targetSum))
{
ans += mappresum[curpresum - targetSum];
}
mappresum[curpresum]++;