二叉树最长路径

(一)递归+回溯

要找到一棵二叉树中从根节点到叶子的最长路径,并打印出这条路径,可以使用 深度优先搜索(DFS) 的方法。具体步骤如下:

  1. 遍历二叉树:从根节点开始,递归遍历每个节点,记录当前路径的长度和路径上的节点。
  2. 更新最长路径:当遍历到叶子节点时,比较当前路径的长度是否比已知的最长路径更长。如果是,则更新最长路径。
  3. 打印路径:在遍历结束后,打印最长路径上的节点。

以下是实现代码(使用 JavaScript):


代码实现

function TreeNode(val, left, right) {
    this.val = (val === undefined ? 0 : val);
    this.left = (left === undefined ? null : left);
    this.right = (right === undefined ? null : right);
}

function findLongestPath(root) {
    if (!root) return { length: 0, path: [] }; // 如果树为空,返回空路径

    let longestPath = { length: 0, path: [] }; // 存储最长路径

    // DFS 递归函数
    const dfs = (node, currentPath) => {
        if (!node) return;

        // 将当前节点加入路径
        currentPath.push(node.val);

        // 如果是叶子节点,检查当前路径是否是最长路径
        if (!node.left && !node.right) {
            if (currentPath.length > longestPath.length) {
                longestPath.length = currentPath.length;
                longestPath.path = [...currentPath]; // 更新最长路径
            }
        }

        // 递归遍历左子树和右子树
        dfs(node.left, currentPath);
        dfs(node.right, currentPath);

        // 回溯:移除当前节点
        currentPath.pop();
    };

    // 从根节点开始 DFS
    dfs(root, []);

    return longestPath;
}

// 示例用法
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
root.right.right = new TreeNode(6);
root.left.left.left = new TreeNode(7);

const result = findLongestPath(root);
console.log("最长路径长度:", result.length); // 输出: 4
console.log("最长路径:", result.path.join(" -> ")); // 输出: 1 -> 2 -> 4 -> 7

代码解释

  1. TreeNode 构造函数

    • 定义了二叉树的节点结构。
  2. findLongestPath 函数

    • 接受二叉树的根节点,返回最长路径的长度和路径。
    • 使用 longestPath 对象存储最长路径的长度和路径。
  3. dfs 递归函数

    • 参数 node 是当前节点,currentPath 是当前路径。
    • 将当前节点的值加入 currentPath
    • 如果当前节点是叶子节点(没有左右子节点),检查当前路径是否比已知的最长路径更长。如果是,则更新 longestPath
    • 递归遍历左子树和右子树。
    • 回溯时,移除当前节点(currentPath.pop()),以便尝试其他路径。
  4. 返回结果

    • 返回 longestPath,包含最长路径的长度和路径。

示例

输入二叉树结构
        1
       / \
      2   3
     / \   \
    4   5   6
   /
  7
输出
最长路径长度: 4
最长路径: 1 -> 2 -> 4 -> 7

复杂度分析

  1. 时间复杂度

    • 每个节点只会被访问一次,时间复杂度为 O(n),其中 n 是二叉树的节点数。
  2. 空间复杂度

    • 递归调用栈的深度为树的高度,最坏情况下为 O(n)(树退化为链表)。
    • 存储路径的空间复杂度为 O(h),其中 h 是树的高度。

总结

通过深度优先搜索(DFS)和回溯,我们可以高效地找到二叉树中从根节点到叶子的最长路径,并打印出这条路径。这种方法适用于任意二叉树,且代码清晰易懂。

(二)迭代+栈

要使用 非递归方法 找到二叉树中从根节点到叶子的最长路径,并打印出这条路径,可以通过 深度优先搜索(DFS) 的迭代实现,结合 来模拟递归过程。以下是实现代码:


非递归实现代码

function TreeNode(val, left, right) {
    this.val = (val === undefined ? 0 : val);
    this.left = (left === undefined ? null : left);
    this.right = (right === undefined ? null : right);
}

function findLongestPath(root) {
    if (!root) return { length: 0, path: [] }; // 如果树为空,返回空路径

    let longestPath = { length: 0, path: [] }; // 存储最长路径
    const stack = []; // 栈用于存储节点和当前路径

    // 初始状态:根节点和空路径
    stack.push({ node: root, path: [root.val] });

    while (stack.length > 0) {
        const { node, path } = stack.pop(); // 弹出栈顶元素

        // 如果是叶子节点,检查当前路径是否是最长路径
        if (!node.left && !node.right) {
            if (path.length > longestPath.length) {
                longestPath.length = path.length;
                longestPath.path = [...path]; // 更新最长路径
            }
        }

        // 将右子节点和当前路径入栈
        if (node.right) {
            stack.push({ node: node.right, path: [...path, node.right.val] });
        }

        // 将左子节点和当前路径入栈
        if (node.left) {
            stack.push({ node: node.left, path: [...path, node.left.val] });
        }
    }

    return longestPath;
}

// 示例用法
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
root.right.right = new TreeNode(6);
root.left.left.left = new TreeNode(7);

const result = findLongestPath(root);
console.log("最长路径长度:", result.length); // 输出: 4
console.log("最长路径:", result.path.join(" -> ")); // 输出: 1 -> 2 -> 4 -> 7

代码解释

  1. TreeNode 构造函数

    • 定义了二叉树的节点结构。
  2. findLongestPath 函数

    • 接受二叉树的根节点,返回最长路径的长度和路径。
    • 使用 longestPath 对象存储最长路径的长度和路径。
  3. 栈的使用

    • 栈中存储的对象包含:
      • node:当前节点。
      • path:从根节点到当前节点的路径。
    • 初始状态:将根节点和路径 [root.val] 入栈。
  4. 迭代过程

    • 弹出栈顶元素,检查当前节点是否是叶子节点。
    • 如果是叶子节点,检查当前路径是否比已知的最长路径更长。如果是,则更新 longestPath
    • 将右子节点和当前路径入栈。
    • 将左子节点和当前路径入栈。
  5. 返回结果

    • 返回 longestPath,包含最长路径的长度和路径。

示例

输入二叉树结构
        1
       / \
      2   3
     / \   \
    4   5   6
   /
  7
输出
最长路径长度: 4
最长路径: 1 -> 2 -> 4 -> 7

复杂度分析

  1. 时间复杂度

    • 每个节点只会被访问一次,时间复杂度为 O(n),其中 n 是二叉树的节点数。
  2. 空间复杂度

    • 栈的最大深度为树的高度,最坏情况下为 O(n)(树退化为链表)。
    • 存储路径的空间复杂度为 O(h),其中 h 是树的高度。

总结

通过栈模拟递归过程,我们可以用非递归方法找到二叉树中从根节点到叶子的最长路径,并打印出这条路径。这种方法避免了递归调用栈的开销,适合处理深度较大的树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值