1、LCR 049. 求根节点到叶节点数字之和
题目信息:
- https://leetcode.cn/problems/3Etpl5/description/
给定一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。
叶节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12
从根到叶子节点路径 1->3 代表数字 13
因此,数字总和 = 12 + 13 = 25
示例 2:
输入:root = [4,9,0,5,1]
输出:1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495
从根到叶子节点路径 4->9->1 代表数字 491
从根到叶子节点路径 4->0 代表数字 40
因此,数字总和 = 495 + 491 + 40 = 1026
提示:
树中节点的数目在范围 [1, 1000] 内
0 <= Node.val <= 9
树的深度不超过 10
解题思路:
- 1、审题:输入一棵二叉树,二叉树中结点值的数据范围为0到9的数字,现在要求找到从根节点到叶子结点组合成的数字,并将這些数字全部相加
- 2、解题:
- 使用前序遍历,将从根节点到叶子结点的组成的数字全部返回,组成数字的规则,是在之前的数字基础上乘以10再加上当前遍历的节点值
- 如果遍历到了空节点则返回0,如果遍历到了叶子结点则返回当前遍历到的数据,如果还存在左右子节点,则继续前序遍历,返回左右子树的组合数字之和
代码实现:
int dfs(TreeNode *node, int num)
{
if (node == nullptr)
{
return 0;
}
int path = num * 10 + node->val;
if (node->left == nullptr && node->right == nullptr)
{
return path;
}
return dfs(node->left, path) + dfs(node->right, path);
}
int sumNumbers(TreeNode *root)
{
return dfs(root, 0);
}
2、LCR 050. 路径总和 III
题目信息:
- https://leetcode.cn/problems/6eUYwP/description/
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例 1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
示例 2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
提示:
二叉树的节点个数的范围是 [0,1000]
-109 <= Node.val <= 109
-1000 <= targetSum <= 1000
解题思路:
- 1、审题:输入一棵二叉树和一个目标值targetSum,要求找到在二叉树中连续节点的值累加和等于目标值的个数
- 2、解题:
- 题目要求在二叉树中连续的结点路径,并没有要求一定要从根节点开始,到叶子结点结束,中间部分的结点路径之和也可以
- 使用前序遍历法,记录遍历到当前结点的路径之和path,
- 使用map保存遍历过程中路径之和和对应个数,这样做的目的可以通过当前路径之和path减去目标值targetSum,判断map中是否存在该差值的键,
- 如果存在则说明到当前结点位置结束,存在一条路径(可能是中间某个节点开始),其路径之和等于目标值
- 相当于在遍历过程中,遍历到每个节点都有一个路径之和path,且都有一个对应的map集合,键值对为路径之和与路径和对应个数的值
- 通过判断路径之和与目标值targetSum之差,来判断结果值是否在map集合中是否存在对应的键
- 因为前序遍历,从根节点开始遍历到左子树再到右子树,path的值是有副本,但是map的值是同一个指针,所以在遍历完当前结点后,需要将到该结点的路径和减去其个数表示退出当前结点
- 在前序遍历的过程中,将所求问题进行拆解,最终的问题是求输入的目标二叉树中路径和等于目标值的个数,可以拆解为三个部分,
- 也就是到当前结点位置的个数,和到左右子树的个数,三者之和
代码实现:
int dfs(TreeNode *node, int target, std::map<double, int> map, double path)
{
if (node == nullptr)
{
return 0;
}
path = path + node->val;
int count = 0;
if (map.find(path - target) != map.end())
{
count = map[path - target];
}
if (map.find(path) != map.end())
{
int tempC = map[path];
map[path] = tempC + 1;
}
else
{
map[path] = 1;
}
count += dfs(node->left, target, map, path);
count += dfs(node->right, target, map, path);
int tempC = map[path];
map[path] = tempC - 1;
return count;
}
int pathSum(TreeNode *root, int targetSum)
{
std::map<double, int> map;
map[0] = 1;
return dfs(root, targetSum, map, 0);
}
3、LCR 051. 二叉树中的最大路径和
题目信息:
- https://leetcode.cn/problems/jC7MId/description/
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。
该路径 至少包含一个 节点,且不一定经过根节点。路径和 是路径中各节点值的总和。
给定一个二叉树的根节点 root ,返回其 最大路径和,即所有路径上节点值之和的最大值。
示例 1:
输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6
示例 2:
输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
提示:
树中节点数目范围是 [1, 3 * 104]
解题思路:
- 1、审题:输入一棵非空的二叉树,要求在这棵二叉树中,查找一条路径上的结点,要求该路径上的所有节点值和最大,并返回这个最大值
- 2、解题:
- 题目要求的该路径没有说要从根节点开始,也没有说要到某个节点结束,可以是树中任意个结点组合成的路径
- 问题的核心为如何找到这个路径,使用后续遍历方式,遍历这棵二叉树,
- 将问题进行细化,可以看做左子树,根节点和右子树三个部分,那这条路径可以有好几种情况:
- 左子树的最大值路径; 右子树的最大值路径; 左子树+根节点+右子树组合成的路径;
- 而在遍历时返回的值,是当前左子树或者左子树经过当前结点组成的路径和的最大值
- 所以每次遍历左右子树的时候,都是传入一个对象引用,
代码实现:
int dfs(TreeNode *node, int &maxSum)
{
if (node == nullptr)
{
return 0;
}
int leftMaxSum = INT32_MIN;
int left = max(0, dfs(node->left, leftMaxSum));
int rightMaxSum = INT32_MIN;
int right = max(0, dfs(node->right, rightMaxSum));
maxSum = max(leftMaxSum, rightMaxSum);
maxSum = max(maxSum, left + right + node->val);
return node->val + max(left, right);
}
int maxPathSum(TreeNode *root)
{
int maxSum = INT32_MIN;
dfs(root, maxSum);
return maxSum;
}
4、总结
- 二叉树的路径和,是对二叉树进行前序遍历,从根节点开始不断遍历到叶子结点的这一条路径所表示的数字之和,分为左右子树,也就是两个路径之和,直到叶子结点返回0.
- 二叉树的一段路径之和,在遍历的过程中既要将路径上的节点值累加,也要记录这个路径和的个数,使用map结构保存路径和与对应的个数
- 二叉树的最大路径和,该路径不要方向,从另一个节点到相邻节点组成的路径和为目标路径和,通过递归的方式,把题目要求缩小来解决。