力扣437题:路径之和
题目描述
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)
输入输出样例
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
Tips
- 二叉树的节点个数的范围是
[0,1000]
-109 <= Node.val <= 109
-1000 <= targetSum <= 1000
解法一,使用深度优先搜索DFS
//使用递归的方法进行实现,DFS(深度优先的算法)
class Solution{
public:
int pathSum(TreeNode *root,int targetSum)
{
if(!root)
{
return 0;
}
//定义初始的数目
int ret=dfs(root,targetSum);
//傻瓜式的遍历其左右的结点
ret+=pathSum(root->left,targetSum);
ret+=pathSum(root->right,targetSum);
return ret;
}
int dfs(TreeNode *root,long target)
{
//定义循环终止的条件
if(!root)
{
return 0;
}
int ret=0;
if(root->val==target)
{
ret++;
}
//若不相等,继续递归其左右的结点,目标值变成其剩余的结点的值
ret+=dfs(root->left,target-root->val);
ret+=dfs(root->right,target-root->val);
return ret;
}
};
解法二,使用前缀和
//使用前缀和 的思想实现
class Solution2
{
public:
int pathSum(TreeNode *root,int targetSum)
{
//建立hash表存储前缀和的值和出现的次数
//key:前缀和 value 出现的次数
unordered_map<long long,int>maps;
//初始化 hash 表
//前缀和为0的一条路径
maps[0]=1;
return dfs(root,maps,targetSum,0);
}
//使用递归实现前缀和
//从当前结点反推到根结点,有且只有一条路径,因为是树
//若此前有和为currSum-target,而当前的和恰为currSum,两者的差肯定是target
//前缀和对于当前路径是唯一的,当前记录的前缀和,在回溯结束,回到本层时进行去除,保证其不影响其他的分支
int dfs(TreeNode *root,unordered_map<long long,int>&maps,int target,long long currSum)
{
//递归终止条件
if(!root)
{
return 0;
}
//记录寻找到的次数
int res=0;
//记录当前路径找到的和
currSum+=root->val;
//查找当前路径上是否存在结点前缀和加target为currSum的路径
//当前结点->root结点反推,有且仅有一条路径,如果此前有和为currSum-target,而当前和有为currSum,则两者差肯定为target
//currSum-target相当于寻找路径的起点,起点的sum+target=currSum,当前点到点的距离就是target
if(maps.count(currSum-target))
{
res=maps[currSum-target];
}
//更新路径上当前结点前缀和的个数
maps[currSum]++;
//进入下一层
res+=dfs(root->left,maps,target,currSum);
res+=dfs(root->right,maps,target,currSum);
//回到本层,恢复状态,去除当前结点的前缀和数量
maps[currSum]--;
return res;
}
};