leetcode
leetcode 201 ~ 250
二叉树的所有路径

二叉树的所有路径

难度:

标签:

题目描述

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

 

示例 1:

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]

示例 2:

输入:root = [1]
输出:["1"]

 

提示:

  • 树中节点的数目在范围 [1, 100]
  • -100 <= Node.val <= 100

代码结果

运行时间: 32 ms, 内存: 15 MB


/*
 * 思路:
 * 1. 使用递归和流来实现深度优先搜索。
 * 2. 如果当前节点是叶子节点,将路径加入结果。
 * 3. 如果当前节点有左或右子节点,递归调用,并连接路径。
 */
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        if (root == null) return new ArrayList<>();
        return dfs(root).collect(Collectors.toList());
    }
 
    private Stream<String> dfs(TreeNode node) {
        if (node.left == null && node.right == null) {
            return Stream.of(Integer.toString(node.val));
        }
        return Stream.concat(
            node.left != null ? dfs(node.left).map(p -> node.val + "->" + p) : Stream.empty(),
            node.right != null ? dfs(node.right).map(p -> node.val + "->" + p) : Stream.empty()
        );
    }
}
 

解释

方法:

该题解使用深度优先搜索(DFS)的方式遍历二叉树。从根节点开始,递归地遍历左右子树,并在遍历过程中维护一个路径数组path。当遇到叶子节点时,将当前路径加入结果数组result中。遍历完一条路径后,需要回溯,即从path中移除当前节点,继续遍历其他路径。

时间复杂度:

O(n*h),其中n为节点数,h为树的高度。最坏情况下O(n^2),最好情况下O(n*log(n))。

空间复杂度:

O(n),其中n为节点数。

代码细节讲解

🦆
为何在遍历完一个节点的左右子树后,需要对path进行回溯(即pop操作)?
在深度优先搜索(DFS)中,回溯是为了确保在遍历树的过程中每次回到父节点时,路径数组path能够准确地反映从根节点到当前节点的路径。执行pop操作是为了移除当前节点,从而在返回父节点后,可以正确地探索其他可能的路径(如兄弟节点)。这样,每次递归调用结束返回上一级调用时,path都会恢复到进入当前节点前的状态,确保路径数组的正确性。
🦆
在DFS遍历中,您如何确保`path`列表在递归的每一层中正确地表示从根节点到当前节点的路径?
在DFS中,每次递归调用时将当前节点的值加入到path列表中。由于递归调用是按照函数调用栈的顺序执行的,因此path列表会随着递归的深入逐步扩展,直到到达叶子节点。在递归返回之前执行pop操作,确保在返回父节点时,从path中移除当前节点,这样path恢复到父节点的状态,为进一步的遍历准备好正确的路径环境。这种方法保证了在每个递归层级,path都精确地表示从根节点到当前节点的路径。
🦆
给定二叉树的节点值可以是负数,这是否对生成路径字符串或结果存储有任何特殊影响?
节点值为负数不会影响DFS的逻辑或路径的存储方式,但它会影响生成的路径字符串的外观。负数会在数字前加上负号('-'),这可能使路径字符串看起来更长或在视觉上更复杂。然而,从技术上讲,处理方式相同,即每个节点值都会被转换为字符串,并用'->'连接起来。因此,无论节点值是正数还是负数,都可以用同样的方法生成和存储路径字符串。
🦆
在您的算法中,是否考虑了二叉树可能存在只有一个节点(即根节点也是叶子节点)的情况?如果有,代码是如何处理这种情况的?
是的,算法确实考虑了二叉树只有一个节点的情况。当二叉树仅有一个节点时,该节点既是根节点也是叶子节点。在DFS函数中,如果一个节点既没有左子树也没有右子树,就会被视为叶子节点。对于只有一个节点的树,DFS会将这个根节点添加到path中,随即检测到它是叶子节点,因此会直接将其路径(即它自己)加入到结果数组。这样,即使树中只有一个节点,也能正确生成其路径。

相关问题

路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

 

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

 

提示:

  • 树中节点总数在范围 [0, 5000]
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

从叶结点开始的最小字符串

给定一颗根结点为 root 的二叉树,树中的每一个结点都有一个 [0, 25] 范围内的值,分别代表字母 'a' 到 'z'

返回 按字典序最小 的字符串,该字符串从这棵树的一个叶结点开始,到根结点结束

字符串中任何较短的前缀在 字典序上 都是 较小 的:

  • 例如,在字典序上 "ab" 比 "aba" 要小。叶结点是指没有子结点的结点。 

节点的叶节点是没有子节点的节点。

 

示例 1:

输入:root = [0,1,2,3,4,3,4]
输出:"dba"

示例 2:

输入:root = [25,1,3,1,3,0,2]
输出:"adz"

示例 3:

输入:root = [2,2,1,null,1,0,null,0]
输出:"abc"

 

提示:

  • 给定树的结点数在 [1, 8500] 范围内
  • 0 <= Node.val <= 25