目录
(一)递归+回溯
要找到一棵二叉树中从根节点到叶子的最长路径,并打印出这条路径,可以使用 深度优先搜索(DFS) 的方法。具体步骤如下:
- 遍历二叉树:从根节点开始,递归遍历每个节点,记录当前路径的长度和路径上的节点。
- 更新最长路径:当遍历到叶子节点时,比较当前路径的长度是否比已知的最长路径更长。如果是,则更新最长路径。
- 打印路径:在遍历结束后,打印最长路径上的节点。
以下是实现代码(使用 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
代码解释
-
TreeNode
构造函数:- 定义了二叉树的节点结构。
-
findLongestPath
函数:- 接受二叉树的根节点,返回最长路径的长度和路径。
- 使用
longestPath
对象存储最长路径的长度和路径。
-
dfs
递归函数:- 参数
node
是当前节点,currentPath
是当前路径。 - 将当前节点的值加入
currentPath
。 - 如果当前节点是叶子节点(没有左右子节点),检查当前路径是否比已知的最长路径更长。如果是,则更新
longestPath
。 - 递归遍历左子树和右子树。
- 回溯时,移除当前节点(
currentPath.pop()
),以便尝试其他路径。
- 参数
-
返回结果:
- 返回
longestPath
,包含最长路径的长度和路径。
- 返回
示例
输入二叉树结构
1
/ \
2 3
/ \ \
4 5 6
/
7
输出
最长路径长度: 4
最长路径: 1 -> 2 -> 4 -> 7
复杂度分析
-
时间复杂度:
- 每个节点只会被访问一次,时间复杂度为
O(n)
,其中n
是二叉树的节点数。
- 每个节点只会被访问一次,时间复杂度为
-
空间复杂度:
- 递归调用栈的深度为树的高度,最坏情况下为
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
代码解释
-
TreeNode
构造函数:- 定义了二叉树的节点结构。
-
findLongestPath
函数:- 接受二叉树的根节点,返回最长路径的长度和路径。
- 使用
longestPath
对象存储最长路径的长度和路径。
-
栈的使用:
- 栈中存储的对象包含:
node
:当前节点。path
:从根节点到当前节点的路径。
- 初始状态:将根节点和路径
[root.val]
入栈。
- 栈中存储的对象包含:
-
迭代过程:
- 弹出栈顶元素,检查当前节点是否是叶子节点。
- 如果是叶子节点,检查当前路径是否比已知的最长路径更长。如果是,则更新
longestPath
。 - 将右子节点和当前路径入栈。
- 将左子节点和当前路径入栈。
-
返回结果:
- 返回
longestPath
,包含最长路径的长度和路径。
- 返回
示例
输入二叉树结构
1
/ \
2 3
/ \ \
4 5 6
/
7
输出
最长路径长度: 4
最长路径: 1 -> 2 -> 4 -> 7
复杂度分析
-
时间复杂度:
- 每个节点只会被访问一次,时间复杂度为
O(n)
,其中n
是二叉树的节点数。
- 每个节点只会被访问一次,时间复杂度为
-
空间复杂度:
- 栈的最大深度为树的高度,最坏情况下为
O(n)
(树退化为链表)。 - 存储路径的空间复杂度为
O(h)
,其中h
是树的高度。
- 栈的最大深度为树的高度,最坏情况下为
总结
通过栈模拟递归过程,我们可以用非递归方法找到二叉树中从根节点到叶子的最长路径,并打印出这条路径。这种方法避免了递归调用栈的开销,适合处理深度较大的树。