思路
-
注意到这题与Path Sum II的不同。第一,path的起点可以不是root,第二,path的终点可以不是leaf。因此,每遍历到一个节点,该节点的左子节点或右子节点可能成为path的起点,pathSum函数专门处理起点的遍历。DFS函数专门处理路径和。
-
在递归的过程中,每次进入递归,将当前节点的val添加至path末尾,然后从path尾部开始往前遍历,若遇到满足条件的路径,则将cnt加一。然后再对左子树和右子树递归,退出递归时,将当前节点的val弹出。
代码
方法1
class Solution {
public:
int pathSum(TreeNode* root, int sum) {
if (!root) return 0;
int cnt = 0;
if (root->val == sum) ++cnt;
cnt += pathSum(root->left, sum);
cnt += pathSum(root->right, sum);
cnt += DFS(root->left, sum - root->val);
cnt += DFS(root->right, sum - root->val);
return cnt;
}
int DFS(TreeNode *root, int sum) {
if (!root) return 0;
int cnt = 0;
if (root->val == sum) ++cnt;
cnt += DFS(root->left, sum - root->val);
cnt += DFS(root->right, sum - root->val);
return cnt;
}
};
方法2
class Solution {
public:
int pathSum(TreeNode* root, int sum) {
if (!root) return 0;
vector<int> vec;
int cnt = 0;
count(root, sum, cnt, vec);
return cnt;
}
void count(TreeNode *root, int sum, int &cnt, vector<int> &vec) {
if (!root) return ;
vec.push_back(root->val);
int s = 0;
for (int i = vec.size() - 1; i >= 0; --i) {
s += vec[i];
if (s == sum) ++cnt;
}
count(root->left, sum, cnt, vec);
count(root->right, sum, cnt, vec);
vec.pop_back();
}
};
方法1 优化代码
class Solution {
public:
int pathSum(TreeNode* root, int sum) {
if (!root) return 0;
int cnt = 0;
dfs(root, sum, cnt);
cnt += pathSum(root->left, sum);
cnt += pathSum(root->right, sum);
return cnt;
}
void dfs(TreeNode *root, int sum, int &cnt) {
if (!root) return ;
if (root->val == sum) ++cnt;
dfs(root->left, sum - root->val, cnt);
dfs(root->right, sum - root->val, cnt);
}
};
总结
对于起点不从root开始的题目,可以一个函数负责遍历起点,一个函数负责遍历以该点为起点的path。也可以从终点的角度开始考虑。方法2中,每次递归,path都有不同的终点,然后从终点往前遍历path,便可找到起点不在root的满足条件的path。