LeetCode/solutions/437. Path Sum III.md

105 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [437. Path Sum III](https://leetcode.com/problems/path-sum-iii/description/)
# 思路
求二叉树中路径和等于sum的路径条数这个路径不一定是从根开始以叶子结束只要求从上到下就行。
## 思路一
最简单的思路,如果这条路径要求必须从根开始,那么这题只需要遍历一遍二叉树就行了。
因此我们考虑遍历一遍二叉树遍历到节点node时就将node作为根节点调用从根开始的路径和函数。则算法具体步骤如下:
* 递归遍历root这课树假设现在遍历到了节点node运行rootpathSum(node, sum)
* rootpathSum(node, sum)计算了所有从node开始的路径的和等于sum的路径条数
* 同时用一个全局变量res对结果进行累加。
运用了两次递归,复杂度有点高。
实际跑出来只击败了30%多...
时间复杂度O(n*n)
## 思路二
思路一递归中还包含递归,因此时间复杂度比较高。
其实我们在先序遍历到某个节点node时从根到此节点路径(设为out)上所有节点都应见过了,
那么我们就应该知道路径out上有多少满足条件且以node结束的子路径了。out定义成一个数组里面存放了从root到node这条路径的所有节点再用curSum记录out里面所有
元素的和每次都要检查out里面是否存在满足条件且以node结束的子路径一个for循环
相对于思路一来说,思路二把思路一的递归改成了循环,运行时间有所下降(击败了80%的人)但是时间复杂度依然是O(n*n)
## 思路三*
不难发现思路二中的每次for循环包含了大量的重复运算我们可以考虑用空间换时间的思想去掉这些不必要的重复计算。
大致思想还是同思路二不过不用out数组记录root到node的所有节点而是用一个hash表mp记录root到(当前)所有节点的每个路径和的个数这样的话mp[curSum - sum]
就是满足条件的且以node结束的路径条数。
例如若root到node的值分别是1、2、3、-3则4个从root开始的路径和分别为1、3、6、3那么此时就有`mp[0] = 1`、`mp[1] = 1`、`mp[3]=2`、`mp[6]=1`。
若sum=2则此时得到的满足条件的且以node结束的路径条数就为`mp[curSum - sum] = mp[3 - 2] = 1`, 这条路径就是“2、3、-3”。
此时击败了99%的人时间复杂度为O(n)
# C++
## 思路一
``` C++
class Solution {
private:
int res = 0;
int rootpathSum(TreeNode *root, int sum){ // 计算从根开始的路径和等于sum的路径条数
if(!root) return 0;
int tmp = 0;
if(root -> val == sum) tmp++;
tmp += rootpathSum(root -> left, sum - root -> val);
tmp += rootpathSum(root -> right, sum - root -> val);
return tmp;
}
void sum_rootpathSum(TreeNode* root, int sum){ // 遍历一遍树将所有的rootpathSum相加
if(!root) return;
res += rootpathSum(root, sum);
sum_rootpathSum(root -> left, sum);
sum_rootpathSum(root -> right, sum);
}
public:
int pathSum(TreeNode* root, int sum) {
sum_rootpathSum(root, sum);
return res;
}
};
```
## 思路二
``` C++
class Solution {
private:
int res = 0;
void helper(TreeNode* node, int sum, int curSum, vector<TreeNode*>& out) {
if (!node) return;
curSum += node->val;
out.push_back(node);
if (curSum == sum) ++res;
int t = curSum;
for (int i = 0; i < out.size() - 1; i++) { // 循环判断以node为结束的子路径中是否有满足条件的
t -= out[i]->val;
if (t == sum) res++;
}
helper(node->left, sum, curSum, out);
helper(node->right, sum, curSum, out);
out.pop_back();
}
public:
int pathSum(TreeNode* root, int sum) {
vector<TreeNode*> out;
helper(root, sum, 0, out);
return res;
}
};
```
## 思路三
``` C++
class Solution {
private:
int helper(TreeNode* node, int sum, int curSum, unordered_map<int, int>& mp) {
if (!node) return 0;
curSum += node->val;
int res = mp[curSum - sum]; // 以node为结束的路径和等于sum的路径条数
mp[curSum]++; // mp记录root到(当前)所有节点的路径和的个数
res += helper(node->left, sum, curSum, mp) + helper(node->right, sum, curSum, mp);
mp[curSum]--;
return res;
}
public:
int pathSum(TreeNode* root, int sum) {
unordered_map<int, int>mp;
mp[0] = 1;
return helper(root, sum, 0, mp);
}
};
```