在二叉树中打印最长的叶到叶路径及其长度

时间:2013-07-17 15:27:11

标签: algorithm binary-tree

我正在解决一个问题,我必须在二叉树中找到最长的叶子到叶子的路径及其长度。

例如,如果二叉树如下:

         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来计算长度。我的观念是否正确?。

另外,我应该如何打印最长的叶对叶路径?我只想要一个想法继续下去。

9 个答案:

答案 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
  }
}

这个想法非常简单:

  1. 我们递归搜索儿童的直径(ldrd以及最大'md')。
  2. 检查通过当前节点的最长可能路径是否比其子节点的直径更大(if (1 + ....))。
  3. 如果它更大,那么我们只需要构建一个带有build函数的新路径,该路径从给定节点't'到叶子的最长路径。因此,我们只使用当前节点连接此函数的两个resuts(对于左右子)。
  4. 如果它不大于那么直径就是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);
 }

这也将确保它找到最长的路径,即使它没有通过根。