437. 路径总和 III
问题描述
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
分析
暴力解法,枚举每个结点开始是否有符合题意的路径,需要dfs枚举起点,从起点开始枚举路径还是dfs,所以是两层dfs。值得注意的是,因为题目中有负数,限制了剪枝:
- 当当前路径结点和大于target时,不能return,因为下一个结点可能是负数,会使得当前路径和再减小
- 当找到res时,不能return,因为下一个结点可能是1,再下一个结点可能是-1,于是还有答案
法一、暴力枚举,两次递归
class Solution {
public:
long long res = 0;
int target_sum = 0;
// 从当前结点开始寻找答案路径
void solve(TreeNode* root, long long x) {
if (root == nullptr) {
return ;
}
x += root->val;
// if (x > target_sum) {
// return ;
// }
if (x == target_sum) {
res++;
// return ;
}
solve(root->left, x);
solve(root->right, x);
}
void dfs(TreeNode* root) {
if (root == nullptr) {
return ;
}
solve(root, 0);
dfs(root->left);
dfs(root->right);
}
int pathSum(TreeNode* root, int targetSum) {
this->target_sum = targetSum;
dfs(root);
return res;
}
};
法二、前缀和+dfs
暴力方法中存在着许多重复计算,判断路径和是否等于某个值,显然想到前缀和。
用um记录在当前路径上从根结点开始的前缀和,由于cur_sum - prefix = sum,所以dfs到每个结点时,检索cur_sum - sum的数量即可,加到res中。而um就是存放当前路径上每个前缀和出现的次数。
class Solution {
public:
unordered_map<long long, int> um; // <在该路径上根结点开始的路径和,出现次数>
int res = 0;
int target_sum = 0;
void solve(TreeNode* root, long long cur_sum) {
if (root == nullptr) {
return ;
}
cur_sum += root->val;
if (um.count(cur_sum - target_sum) != 0) { // 注意,这里的顺序,应该先判断res,然后再把当前cur_sum插入到um
res += um[cur_sum-target_sum];
}
if (um.count(cur_sum) == 0) {
um.insert(make_pair(cur_sum, 1));
} else {
um[cur_sum]++;
}
solve(root->left, cur_sum);
solve(root->right, cur_sum);
um[cur_sum]--; // 回溯
}
int pathSum(TreeNode* root, int targetSum) {
this->target_sum = targetSum;
um.insert(make_pair(0,1));
solve(root, 0);
return res;
}
};
分类:
Algorithm Note
标签:
hot100
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!