1. 问题描述:
给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。
例如,从根到叶子节点路径 1->2->3 代表数字 123。
计算从根到叶子节点生成的所有数字之和。
说明: 叶子节点是指没有子节点的节点。
示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.
示例 2:
输入: [4,9,0,5,1]
4
/ \
9 0
/ \
5 1
输出: 1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495.
从根到叶子节点路径 4->9->1 代表数字 491.
从根到叶子节点路径 4->0 代表数字 40.
因此,数字总和 = 495 + 491 + 40 = 1026.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-root-to-leaf-numbers
2. 思路分析:
① 题目不难理解,因为二叉树的很多操作都是可以使用递归来完成的,特别是像这种关于路径的上的相关操作,使用递归来解决是比较常用的方法,因为递归是先纵后横,所以会尝试所有的路径,所以我们可以利用这个特点来计算二叉树上的所有路径之和
② 在递归的时候分别递归左子树与右子树,并且在下一次递归的时候需要计算到达当前节点的路径之和,这个计算很简单在每一次计算的时候都是上一次的路径之和乘以10再加上当前这个节点的值,然后往下进行对于左子树与右子树进行递归即可,在出口的时候当发现是叶子节点的时候计算到达最后一个节点的路径总和,然后return即可,递归会返回上一层的,尝试其他的路径,并且使用全局变量来进行路径上的和的累加,每一次到达叶子节点的时候都表示新的一条路径已经产生,那么这个时候将这条路径的值累加到全局变量上即可,所以在方法中需要使用一个变量来记录到达当前节点路径之和,等到递归结束的时候全局变量的结果就是所有的路径之和
③ 在写代码的时候可能遇到一些没用考虑到的细节出现的错误,这个时候使用idea的debug调试很有用,在debug的时候执行每一步并且预判结果是什么,这个时候根据中间结果可以大概推测哪里出现了问题,并且领扣提交的时候假如错误了会显示什么地方错了,这个时候结合具体的测试用例和分析推测错误在哪里从而解决错误
④ 在写这些关于二叉树的相关操作代码的时候结合具体的例子画出图可以很方便地解决其中的细节问题这样的话可以节省写代码与调试代码的时间
⑤ 为了方便测试我还自己创建一棵二叉树进行模拟,这样在idea测试的时候会比较方便,首先可以新建一个TreeNode数组,在for循环中进行初始化,然后再在另外一个循环中建立节点之间的关系,利用数组的下标与叶子节点与根节点之间的关系,根节点i的左右节点为2 * i + 1与2 * i + 2,分别连接上对应的左右子树,写完之后可以使用二叉树的遍历方法对代码进行测试看一下生成的二叉树是否是正确的
⑥ 看了领扣的题解之后,发现领扣中可以直接使用有返回值的递归这样代码的话会很简洁,分别将左右子树的路径然后将路径之后加起来即可,很值得学习一下
3. 代码如下:
提交到领扣代码:
import java.util.Scanner;
public class Solution {
/*使用一个全局变量来记录中间的结果, 注意提交的时候需要去掉static否则是错误的*/
int res = 0;
public int sumNumbers(TreeNode root) {
if (root == null) return 0;
solve(root,0);
return res;
}
/*路径之和是上一次的结果乘以10再加上当前节点的值*/
public void solve(TreeNode root, int curSum) {
/*本身节点为空的情况*/
if (root == null) return;
/*叶子节点*/
if (root.left == null && root.right == null) {
/*这里注意要乘以10再加上当前节点的值因为最后一个叶子节点需要加上
* 在debug调试的时候比较容易发现其中的错误
* */
curSum = curSum * 10 + root.val;
res += curSum;
return;
}
/*左右子树进行递归*/
solve(root.left, curSum * 10 + root.val);
solve(root.right, curSum * 10 + root.val);
}
}
测试代码,在控制台中可以输入数字序列建立二叉树:
import java.util.Scanner;
public class Solution {
public static class TreeNode{
private TreeNode left;
private TreeNode right;
private int val;
public TreeNode(int val) {
this.val = val;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int arr[] = new int[n];
for (int i = 0; i < n; ++i){
arr[i] = sc.nextInt();
}
TreeNode root = createBinaryTree(arr);
System.out.println(sumNumbers(root));
}
/*首先是需要创一颗二叉树: 通过数组的下表与二叉树根节点与叶子节点之间的关系来创建一颗二叉树*/
private static TreeNode createBinaryTree(int[] arr) {
TreeNode nodeArr[] = new TreeNode[arr.length];
/*初始化*/
for (int i = 0; i < arr.length; ++i){
nodeArr[i] = new TreeNode(arr[i]);
}
for (int i = 0; i < arr.length; ++i){
int l = 2 * i + 1;
int r = 2 * i + 2;
if (l < arr.length) nodeArr[i].left = nodeArr[l];
else nodeArr[i].left = null;
if (r < arr.length) nodeArr[i].right = nodeArr[r];
else nodeArr[i].right = null;
}
//preOrder(nodeArr[0]);
return nodeArr[0];
}
/*前序遍历检查是否正确*/
private static void preOrder(TreeNode node) {
if (node == null) return;
System.out.println(node.val);
preOrder(node.left);
preOrder(node.right);
}
/*使用一个全局变量来记录中间的结果*/
static int res = 0;
public static int sumNumbers(TreeNode root) {
/*注意空树的时候直接返回0即可*/
if (root == null) return 0;
solve(root,0);
return res;
}
/*路径之和是上一次的结果乘以10再加上当前节点的值*/
private static void solve(TreeNode root, int curSum) {
/*本身节点为空的情况*/
if (root == null) return;
/*叶子节点*/
if (root.left == null && root.right == null) {
curSum = curSum * 10 + root.val;
res += curSum;
return;
}
/*左右子树进行递归*/
solve(root.left, curSum * 10 + root.val);
solve(root.right, curSum * 10 + root.val);
}
}