我正在解决一个问题,我必须在二叉树中找到最长的叶子到叶子的路径及其长度。
例如,如果二叉树如下:
a
/\
b c
/ / \
d e f
/ \ \
g h p
\
k
最长的叶子到叶子的路径是 k-h-d-b-a-c-f-p ,其长度 8 。
我通过递归地找到左右子树的长度然后return height_left + height_right + 1
来计算长度。我的观念是否正确?。
另外,我应该如何打印最长的叶对叶路径?我只想要一个想法继续下去。
答案 0 :(得分:4)
在我看来,这个算法非常接近于找到二叉树的直径。树的直径是树中两个叶子之间最长路径上的节点数。
我认为你可以在这里查看实现:http://www.geeksforgeeks.org/diameter-of-a-binary-tree/然后根据需要调整或优化它的时间复杂度。但我认为O(n)
足够好了。
答案 1 :(得分:3)
网上的大多数答案都给出了如何找到树的直径,即 如何查找最长路径中的节点数。
唯一的补充是我们需要存储有助于它的节点。
在递归中,这可以通过两种方式完成。
a)应该是返回类型
b)它应该是一个输入参数,它是一个对象。在递归过程中使用结果填充此对象。
无需打印最长路径,我们只需要检查每个节点:
最大的
1)左节点最大路径
2)右节点最大路径
c)当前节点最大路径(需要更多输入)
现在,要计算当前节点最大路径,我们需要更多输入:
当前节点最大路径需要:
1)最大左节点高度
2)最大右节点高度
这可以存储在节点本身(作为height参数),也可以与递归一起传递。
这只会给出最长路径的直径/长度。
现在,为了打印路径,我们需要存储更多信息,即:
- List<Nodes> pathList
- 这包含到目前为止形成最长路径的节点(注意,这可能不包含当前节点)。
- List<Nodes> heightList
- 包含从节点到其叶子形成最长高度的节点。
最后算法:
//方法的输入和输出
class Node{
int value;
Node leftchild;
Node rightchild;
}
class ReturnInfo{
ReturnInfo(){
maxpathlen = 0;
maxheight = 0;
pathList = new ArrayList<Node>();
heightList = new ArrayList<Node>();
}
int maxpathlen; //current max path
int maxheight; //current max height
List<Nodes> pathList;
List<Nodes> heightList;
}
//签名 public ReturnInfo getMaxPath(Node n);
//实施
public ReturnInfo getMaxPath(Node n){
//Base case
if(n==null) return new ReturnInfo();
//This is a bottom up recursion. Info will flow from leaves to root.
//So first recurse and then do the work at this node level
//Recurse left & right
ReturnInfo leftReturnInfo = getMaxPath(n.leftchild);
ReturnInfo rightReturnInfo = getMaxPath(n.rightchild);
//Do work in this recursion or for this node
ReturnInfo retInfo = new ReturnInfo();
//Update all 4 parameters of returninfo and we are done
retInfo.maxheight = max(leftReturnInfo.maxheight, rightReturnInfo.maxheight) + 1;
//Update retInfo.heightList accordingly
retInfo.heightList = ....
retInfo.maxPathLen = max(leftReturnInfo.maxPathLen, rigthReturnInfo.maxPathLen, leftReturnInfo.maxHeight+rightReturnInfo.maxHeight+1);
//Remember from where maxPathLen came from and update accordingly
retInfo.pathList = .....
return retInfo;//We are done
}
答案 2 :(得分:1)
您需要一个函数返回子树中最长的分支和最长的路径:
PS:我遗漏了细节(例如边界条件等)。但这应该给你一个想法。这个函数返回两个'branch'和'path'。 'branch'是从该节点到其任何叶子的最长路径。 'path'是这个子树中任意两个叶子之间最长的路径。
def longestPath(node):
(leftBranch, leftPath) = longestPath(node.left);
(rightBranch, rightPath) = longestPath(node.right);
if len(rightBranch) > len(leftBranch):
curBranch = rightBranch+node.name
else:
curBranch = leftBranch+node.name
curPath = leftBranch + node.name + rev(rightBranch)
bestPath = curPath
if len(leftPath) > length(bestPath):
bestPath = leftPath
if len(rightPath) > length(bestPath):
bestPath = rightPath
return (curBranch, bestPath)
答案 3 :(得分:1)
defintion:
node: (char content, node left , node right , node parent)
add(list , node): add node as last element in list
remove(list , index): remove and return element at index in list
length(string): length of string
insert(string , char , index): insert char at index in string
concat(string a , string OR char b): append b to a
input: node start
output: string
start
list nodes
node n
add(nodes , start)
do
n = remove(nodes , 0)
if n.parent != null
add(nodes , n.parent)
if n.left != null
add(nodes , n.left)
if n.right != null
add(nodes , n.right)
while !isEmpty(nodes)
//n now is the node with the greatest distance to start
string left = ""
string right = ""
node a = start
node b = n
while(a != b)
insert(left , a.content , length(left) - 1)
insert(right , b.content , 0)
a = a.parent
b = b.parent
string result = left
concat(result , a.content)
concat(result , right)
return result
答案 4 :(得分:0)
以下是my Scala solution (Tree.scala):
/** Searches for the longest possible leaf-to-leaf path in this tree.
*
* Time - O(log^2 n)
* Space - O(log n)
*/
def diameter: List[A] = {
def build(t: Tree[A], p: List[A]): List[A] =
if (t.isEmpty) p
else if (t.left.height > t.right.height) build(t.left, t.value :: p)
else build(t.right, t.value :: p)
if (isEmpty) Nil
else {
val ld = left.diameter
val rd = right.diameter
val md = if (ld.length > rd.length) ld else rd
if (1 + left.height + right.height > md.length)
build(right, value :: build(left, Nil).reverse).reverse
else md
}
}
这个想法非常简单:
ld
和rd
以及最大'md')。if (1 + ....)
)。build
函数的新路径,该路径从给定节点't'到叶子的最长路径。因此,我们只使用当前节点连接此函数的两个resuts(对于左右子)。md
。答案 5 :(得分:0)
叶子到叶子的最长路径意味着找到树的直径。它可以使用高度函数完成。
网上有很多解决方案。
答案 6 :(得分:0)
这是我的Swift解决方案:
func diameterPath() -> [T] {
return diameterPathHelper(root).Path
}
typealias HeightAndDiameterAndPath = (Height: Int, Diameter: Int, Path: [T])
private func diameterPathHelper(node: TreeNode<T>?) -> HeightAndDiameterAndPath {
guard let node = node else {
return HeightAndDiameterAndPath(0, 0, [])
}
let left = diameterPathHelper(node.left)
let right = diameterPathHelper(node.right)
let height = max(left.Height, right.Height) + 1
if left.Height + right.Height + 1 > max(left.Diameter, right.Diameter) {
let currentDiameter = left.Height + right.Height + 1
let path = left.Path + [node.data] + right.Path
return HeightAndDiameterAndPath(height, currentDiameter, path)
} else {
if left.Diameter > right.Diameter {
return HeightAndDiameterAndPath(height, left.Diameter, left.Path)
} else {
return HeightAndDiameterAndPath(height, right.Diameter, right.Path)
}
}
}
答案 7 :(得分:0)
我们可以使用maxdepth方法并将变量max初始化为0。
public int diameterOfBinaryTree(TreeNode root) {
maxDepth(root);
return max;
}
private int maxDepth(TreeNode root) {
if (root == null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
max = Math.max(max, left + right);
return Math.max(left, right) + 1;
}
}
答案 8 :(得分:0)
你忽略了一个条件:如果最长的路径没有通过根节点怎么办?
static int findLongestPathLength(Node root){
if(root == null)
return 0;
int lh = getHeight(root.left);
int rh = getHeight(root.right);
return Math.max(1+lh+rh,
Math.max(findLongestPathLength(root.left),findLongestPathLength(root.right)));
}
static int getHeight(Node root){
if(root == null)
return 0;
return Math.max(getHeight(root.left)+1, getHeight(root.right)+1);
}
这也将确保它找到最长的路径,即使它没有通过根。