题目描述
知识点
树、DFS、前缀和
我的傻逼解法
结果
思路
- 使用
vector
返回所有的子路径… - 啊,我这个方法未免太蠢了吧,我好笨。
代码
//我能想到的只有返回 当前结点的所有路径和vector
class Solution {
public:
int cnt=0;
int target;
int pathSum(TreeNode* root, int sum) {
target=sum;
dfs(root);
return cnt;
}
vector<int> dfs(TreeNode* root){
if(root == NULL){
return vector<int>();
}
vector<int> left = dfs(root->left);
vector<int> right = dfs(root->right);
vector<int> cur;
cur.push_back(root->val);
if(root->val == target){
cnt++;
}
int newVal;
for(auto i : left){
newVal = i+root->val;
if(newVal == target){
cnt++;
}
cur.push_back(newVal);
}
for(auto i : right){
newVal = i+root->val;
if(newVal == target){
cnt++;
}
cur.push_back(newVal);
}
return cur;
}
};
双重DFS解法
结果
思路
① 先序递归遍历每个节点
② 以每个节点作为起始节点DFS寻找满足条件的路径
- 我们知道,每个结点都有可能作为路径的起点,所以就首先遍历每个结点。然后再以结点作为开始,进行暴力dfs(需要传递一个sum,用于保存当前路径和)。
- 解题的要点就是要想到每个结点都有可能是路径起点,然后dfs遍历所有路径即可。
代码
/**
* 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 cnt=0;
//pathSum用于返回root为根节点的子树的所有可能情况。
int pathSum(TreeNode* root, int sum) {
if(root==NULL){
return 0;
}
dfs(root,sum);
pathSum(root->left,sum);
pathSum(root->right,sum);
return cnt;
}
//dfs只返回以当前根节点为路径起点的所有可能情况
void dfs(TreeNode* root,int sum){
if(root == NULL){
return;
}
sum -= root->val;
if(sum == 0){
cnt++;
}
dfs(root->left,sum);
dfs(root->right,sum);
return;
}
};
前缀和解法
结果
思路
这道题用到了一个概念,叫前缀和。就是 到达当前元素的路径上,之前所有元素的和。
前缀和怎么应用呢?
如果两个数的前缀总和是相同的,那么这些节点之间的元素总和为零。进一步扩展相同的想法,如果前缀总和currSum,在节点A和节点B处相差target,则位于节点A和节点B之间的元素之和是target。
因为本题中的路径是一棵树,从根往任一节点的路径上(不走回头路),有且仅有一条路径,因为不存在环。(如果存在环,前缀和就不能用了,需要改造算法)
抵达当前节点(即B节点)后,将前缀和累加,然后查找在前缀和上,有没有前缀和currSum-target的节点(即A节点),存在即表示从A到B有一条路径之和满足条件的情况。结果加上满足前缀和currSum-target的节点的数量。然后递归进入左右子树。
左右子树遍历完成之后,回到当前层,需要把当前节点添加的前缀和去除。避免回溯之后影响上一层。因为思想是前缀和,不属于前缀的,我们就要去掉它。
时间复杂度:每个节点只遍历一次,O(N).
空间复杂度:开辟了一个hashMap,O(N).
作者:burning-summer
链接:https://leetcode-cn.com/problems/path-sum-iii/solution/qian-zhui-he-di-gui-hui-su-by-shi-huo-de-xia-tian/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码
class Solution {
public:
unordered_map<int,int> mp;
int ans;
int pathSum(TreeNode* root, int sum) {
ans=0;
mp[0]=1; //这里很重要!
dfs(root,sum,0);
return ans;
}
void dfs(TreeNode* root,int sum,int prefixSum){
if(!root){
return;
}
//得到当前前缀和
int curSum = prefixSum + root->val;
int remain = curSum - sum;
if(mp.count(remain) != 0){
ans += mp[remain];
}
mp[curSum]++;
dfs(root->left,sum,curSum);
dfs(root->right,sum,curSum);
mp[curSum]--;
return;
}
};
反思
- 前缀和让我眼前一亮,看来 前缀和中使用hashMap才是王道 !之前学的数组啥的还只是小case!