leetcode
leetcode 1251 ~ 1300
二叉树中的最长交错路径

二叉树中的最长交错路径

难度:

标签:

题目描述

给你一棵以 root 为根的二叉树,二叉树中的交错路径定义如下:

  • 选择二叉树中 任意 节点和一个方向(左或者右)。
  • 如果前进方向为右,那么移动到当前节点的的右子节点,否则移动到它的左子节点。
  • 改变前进方向:左变右或者右变左。
  • 重复第二步和第三步,直到你在树中无法继续移动。

交错路径的长度定义为:访问过的节点数目 - 1(单个节点的路径长度为 0 )。

请你返回给定树中最长 交错路径 的长度。

 

示例 1:

输入:root = [1,null,1,1,1,null,null,1,1,null,1,null,null,null,1,null,1]
输出:3
解释:蓝色节点为树中最长交错路径(右 -> 左 -> 右)。

示例 2:

输入:root = [1,1,1,null,1,null,null,1,1,null,1]
输出:4
解释:蓝色节点为树中最长交错路径(左 -> 右 -> 左 -> 右)。

示例 3:

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

 

提示:

  • 每棵树最多有 50000 个节点。
  • 每个节点的值在 [1, 100] 之间。

代码结果

运行时间: 348 ms, 内存: 61.5 MB


/*
 * 思路:
 * 1. 使用递归和Stream API遍历二叉树。
 * 2. 在每个节点上使用Stream遍历其左右子树并计算最长交错路径。
 * 3. 使用IntStream来计算每个方向的最大长度。
 */

import java.util.stream.IntStream;

class Solution {
    public int longestZigZag(TreeNode root) {
        return IntStream.of(dfs(root.left, false, 1), dfs(root.right, true, 1)).max().orElse(0) - 1;
    }

    private int dfs(TreeNode node, boolean isRight, int length) {
        if (node == null) return length - 1;
        return isRight ?
            Math.max(dfs(node.left, false, length + 1), dfs(node.right, true, 1)) :
            Math.max(dfs(node.right, true, length + 1), dfs(node.left, false, 1));
    }
}

解释

方法:

本题解采用了深度优先搜索(DFS)的方法来解决二叉树的最长交错路径问题。首先定义一个全局变量 `longest` 来存储目前找到的最长路径长度。接着,定义一个递归函数 `dfs` 来探索每个节点,该函数接受当前节点、当前路径的长度 `depth`,以及一个布尔值 `isLeft` 指示当前的方向(左或右)。函数中,首先更新 `longest` 为当前路径长度和 `longest` 的较大值。如果当前节点为 `None`,则直接返回。根据当前的方向,递归调用左子或右子节点,并调换方向。最后,从根节点的左子和右子开始分别调用 `dfs` 函数,初始化方向分别为左和右,以探索所有可能的交错路径。最终,返回 `longest` 作为结果。

时间复杂度:

O(n)

空间复杂度:

O(h)

代码细节讲解

🦆
为什么在递归函数中,当改变方向时,路径长度depth要增加,但重新开始一个方向时,depth却重置为0?
在递归函数中,路径长度depth的增加反映了当前节点到其子节点的有效交错路径的延伸。每次递归调用时改变方向并增加depth,是为了模拟交错路径的连续性。当重新开始一个方向时,depth被重置为0,是因为你正在从新的节点开始探索新的交错路径,因此需要重新计算路径长度。这样做是为了确保每个节点都可以作为交错路径的起点,以发现可能的更长路径。
🦆
在递归过程中,对于没有子节点的叶子节点,函数如何处理,它是否会影响最长路径的计算?
在递归过程中,当遇到叶子节点(即没有子节点的节点),函数会检查当前节点,更新最长路径长度后,因为无子节点可递归,所以递归调用将结束。叶子节点作为路径的终点,其存在是至关重要的,因为它们代表了路径的结束。虽然它们不会直接延伸路径,但它们在计算最长路径时起到了关键角色,因为路径的长度在达到叶子节点时达到最大值。
🦆
您提到使用了全局变量`longest`来记录最长路径长度,这种方法在多线程环境下是否会引发问题,如果会,有什么替代方案?
使用全局变量`longest`在单线程环境下没有问题,但在多线程环境中,多个线程可能会同时修改这个变量,导致数据竞态和不一致的情况。作为替代方案,可以考虑使用线程局部存储来保持每个线程的`longest`副本,或者在每个线程完成后使用锁或其他同步机制来合并结果。另一种方法是避免使用全局变量,改用递归函数返回当前最长路径的长度,并通过参数传递来累加或比较长度。
🦆
递归函数`dfs`没有返回任何值,这是基于什么考虑?是否有可能通过返回值来优化代码的执行效率?
递归函数`dfs`没有返回值是因为它通过修改外部变量`longest`来间接记录状态。这种设计简化了状态管理,但有时可能不是最高效的做法。通过让`dfs`返回当前节点的最长路径长度,我们可以避免使用全局变量,并可能提高代码的清晰性和效率。这样,每个递归调用都会贡献其子树的最长路径长度,可以在每个节点处更有效地比较和合并路径长度。

相关问题