1.路径总和 (1)
Given the
root
of a binary tree and an integertargetSum
, returntrue
if the tree has a root-to-leaf path such that adding up all the values along the path equalstargetSum
.A leaf is a node with no children.
Example 1:
Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 Output: true Explanation: The root-to-leaf path with the target sum is shown.Example 2:
Input: root = [1,2,3], targetSum = 5 Output: false Explanation: There two root-to-leaf paths in the tree: (1 --> 2): The sum is 3. (1 --> 3): The sum is 4. There is no root-to-leaf path with sum = 5.Example 3:
Input: root = [], targetSum = 0 Output: false Explanation: Since the tree is empty, there are no root-to-leaf paths.Constraints:
- The number of nodes in the tree is in the range
[0, 5000]
.-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
以上是路径总和(1)的题目,
题目大致的意思是在一颗二叉树中寻找一个路径,使得经过的二叉树节点之和为给定数值。如果能够找到这样的路径,就返回true,如果不能找到,那就返回false。
思路:
首先明确一点,就是这棵树必须得全部遍历了,其次,这棵树的遍历是需要从根节点走到叶子节点的,这一条路径的总和须满足给定数值(有两种方法累积节点,一个是加,一个是减,本思路采用减法进行数值累积)。
遍历这棵树,我这边采用的方式是递归的方式。
- 先确定递归出口,明确,当前节点为空时,就返回false。
- 后考虑判断条件,因为这个路径的最终是要走到叶子节点的, 所以,我们需要考虑一下叶子节点的判断条件,以及是否满足总和为给定数值的条件。
- 遍历当前节点的左右子树。
确立好了解题思路后,我们就可以明确代码了,代码较为简单
/**
* 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:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false; // 递归出口
if (root->left == nullptr && root->right == nullptr) return targetSum == root->val;
// 判断是否是叶子节点,同时返回的结果代表当前是否与给定数值相符合。
return hasPathSum(root->left,targetSum-root->val) || hasPathSum(root->right,targetSum-root->val);
// 只要左右节点的递归遍历有一个满足就行啦,所以用 || 连接逻辑判断
}
};
2. 路径总和 (2)
Given the root
of a binary tree and an integer targetSum
, return all root-to-leaf paths where the sum of the node values in the path equals targetSum
. Each path should be returned as a list of the node values, not node references.
A root-to-leaf path is a path starting from the root and ending at any leaf node. A leaf is a node with no children.
Example 1:
Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 Output: [[5,4,11,2],[5,8,4,5]] Explanation: There are two paths whose sum equals targetSum: 5 + 4 + 11 + 2 = 22 5 + 8 + 4 + 5 = 22
Example 2:
Input: root = [1,2,3], targetSum = 5 Output: []
Example 3:
Input: root = [1,2], targetSum = 0 Output: []
Constraints:
- The number of nodes in the tree is in the range
[0, 5000]
. -1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
由于这是一个系列的题型,所以题目意思会稍显相近,本题的难点在于,题目要求返回一个二维的vector,同时vector里面记录了满足条件的节点,每一个一维的vector 代表一条符合条件的路径之和,这里面就牵涉到了递归的回溯问题,我们是否需要选择这个当前元素,代码稍长一些,但是需要保证逻辑清晰。
思路 :
因为题目要求返回一个二维vector,所以我们不能在原函数里面递归,因为我这边不知道怎么去在函数里面递归处理,所以,我新建立了一个函数,用它将我们需要的vector跑好,最后再由原函数返回即可。
首先思考一下题目,很显然,我们需要有回溯,同时,我们还要遍历全部的节点。
所以,我们先可以进行树的遍历,
既然开始遍历,那么还是三步走,递归出口,判断条件,结果返回。
- 递归出口
- 当前节点为nullptr的时候,肯定是要返回的。
- 当前节点为叶子节点,同时满足路径总和为所给定的数值,即可将当前一维vector传入二维vector,说明已经找到一条符合条件的路径了,就可以返回了。
- 若当前节点为叶子节点,同时不满足条件时,那就算啦,他都不满足条件了,肯定是不能放在二维的vector里面的,返回就行。
- 判断条件
- 如果左子树不为空,那么我们可以先行记录下来,将当前节点的左儿子数值丢到一维的vector里面,反正咱要回溯的,所以先丢为敬,同时,目标数值减去当前节点的左儿子数值。并开始当前节点的左儿子的遍历。之后回溯就好,抹除不符合条件的遍历。
- 如果右子树不为空,与上同理。
- 结果返回
- 直接返回返回 return; 就好了,前面的递归已经将vector数组全部处理好了,这个函数的功能就完全实现了,后面的结果就不需要返回太多。
代码稍显混乱,但是其中逻辑需要好好明确。
/**
* 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:
vector<vector<int>> result;
vector<int> path;
void traversal(TreeNode* root,int sum) {
if (root == nullptr) return ;
if (root->left == nullptr && root->right == nullptr && sum == 0){
result.push_back(path);
return ;
}
if (root->left == nullptr && root->right == nullptr){
return ;
}
if (root->left != nullptr){
path.push_back(root->left->val);
sum -= root->left->val;
traversal(root->left,sum);
sum += root->left->val;
path.pop_back();
}
if (root->right != nullptr){
path.push_back(root->right->val);
sum -= root->right->val;
traversal(root->right,sum);
sum += root->right->val;
path.pop_back();
}
return ;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
result.clear();
path.clear();
if (root == nullptr) return result;
path.push_back(root->val);
traversal(root,targetSum-root->val);
return result;
}
};
3. 路径总和(3)
Given the root
of a binary tree and an integer targetSum
, return the number of paths where the sum of the values along the path equals targetSum
.
The path does not need to start or end at the root or a leaf, but it must go downwards (i.e., traveling only from parent nodes to child nodes).
Example 1:
Input: root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8 Output: 3 Explanation: The paths that sum to 8 are shown.
Example 2:
Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 Output: 3
Constraints:
- The number of nodes in the tree is in the range
[0, 1000]
. -109 <= Node.val <= 109
-1000 <= targetSum <= 1000
上为题目,这个路径总和(3)就有意思啦,怎么说?这个首先是去掉一定要从根节点走到叶子节点的限制
要求,从任意一个节点出发,只要满足给定数值,就行,非常的野,这种题目有意思就好好想想
思路:
- 首先,他必须遍历完所有节点,因为我只要从任意一个节点开始的路径,符合条件就好
- 确定从当前节点开始遍历。
- 特别划重点注意:如果当前节点凑够了目标数值,并不需要直接返回,因为本题会出现负数节点,若叶子节点走出的路径出现更长的一条满足,那么那一条也是可以的。
显然,我们可以确定,需要有一个主遍历,即遍历整棵树的遍历,他用于统计总和路径,并返回总和答案
其次,我们需要一个副遍历,就是从当前节点开始的遍历,我们需要记录从当前节点遍历开始,有多少条路 径符合答案结果,这个的返回值时当前节点开始,满足条件的路径数量。
于是我们的代码就比较清晰了,这个思路是可以的。
class Solution {
public:
int work(TreeNode* root,long targetSum) {
if (root == nullptr) return 0;
int ret = 0;
if (root->val == targetSum) ret++; // 这里面非常重要
ret += work(root->left,targetSum - root->val);
ret += work(root->right,targetSum - root->val);
return ret;
}
int pathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return 0;
int ret = work(root,targetSum);
ret += pathSum(root->left,targetSum);
ret += pathSum(root->right,targetSum);
return ret;
}
};