微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

对二叉树的最大直径问题感到困惑

如何解决对二叉树的最大直径问题感到困惑

不确定这是如何工作的...

class TreeNode:
  def __init__(self,val,left=None,right=None):
    self.val = val
    self.left,self.right = left,right

  def find_diameter(self,root):
    self.calculate_height(root)
    return self.treeDiameter

  def calculate_height(self,currentNode):
    if currentNode is None:
      return 0

    leftTreeDiameter = self.calculate_height(currentNode.left)
    rightTreeDiameter = self.calculate_height(currentNode.right)

    diameter = leftTreeDiameter + rightTreeDiameter + 1
    self.treeDiameter = max(self.treeDiameter,diameter)

    return max(leftTreeDiameter,rightTreeDiameter) + 1

以上代码用于获取二叉树的最大直径,但我不明白 calculate_height 中的最后一行。为什么我们需要返回 max(leftTreeDiameter,rightTreeDiameter) + 1

我显然不明白,但我所知道的是,对于每个 currentNode,我们将继续沿着树的左侧向下移动,然后类似地对右侧执行相同的操作。如果我们最终没有节点(意思是在我们处于叶节点之前),那么我们将返回 0,因为我们不想为不存在的节点添加 1。

似乎添加除 0 之外的任何内容的唯一地方是 calculate_height 中的最后一行代码,因为尽管我们添加leftTreeDiameter + rightTreeDiameter + 1 以获得总直径,但这只是因为 {{ 1}} 和 return 0 正确吗?

另外,我对为什么可以为 leftTreeDiameter 分配 return max(leftTreeDiameter,rightTreeDiameter) + 1 感到困惑。我的意思是,我认为我需要类似......

self.calculate_height(currentNode.left)

我们每次只在高度上加 1。在这种情况下,我没有做类似 def calculate_left_height(self,currentNode,height=0): if currentNode is None: return 0 self.calculate_height(currentNode.left,height + 1) return height 之类的操作,而是在每次看到节点时将其作为参数 leftTreeDiameter += self.calculate_height(currentNode.left) 传入。

但如果我这样做,我将需要一个单独的方法来计算正确的高度,并且在我的 height + 1 方法中需要使用 find_diameterfind_diameter 递归调用 root.leftroot.right

我的逻辑哪里错了,calculate_height 是如何工作的。我想我在试图弄清楚如何跟踪堆栈时遇到了麻烦?

解决方法

此代码中使用的名称令人困惑:leftTreeDiameterrightTreeDiameter 不是直径,而是高度。

其次,函数calculate_height有副作用,不是很好。一方面它返回一个高度,同时它分配一个直径。这令人困惑。许多 Python 编码人员更喜欢纯函数,并且只返回某些东西,而不改变其他任何东西。或者,一个函数只能改变某些状态而返回它。两者都做可能会令人困惑。

另外,虽然类被称为TreeNode,但它的find_diameter方法仍然需要一个节点作为参数,这一点令人困惑。这是违反直觉的。我们希望该方法将 self 作为要操作的节点,而不是参数。

但让我们重命名变量并添加一些注释:

leftHeight = self.calculate_height(currentNode.left)
rightHeight = self.calculate_height(currentNode.right)

# What is the size of the longest path from leaf-to-leaf 
#   whose top node is the current node?
diameter = leftHeight + rightHeight + 1
# Is this path longer than the longest path that we
#   had found so far? If so,take this one.
self.treeDiameter = max(self.treeDiameter,diameter)
# The height of the tree rooted at the current node
#   is the height of the highest childtree (either left or right),#   with one added to account for the current node
return max(leftHeight,rightHeight) + 1

应该很清楚,但是要意识到,这个过程中的 self 始终是调用 find_diameter 方法的实例,并没有真正扮演实际节点的角色,作为根作为参数传递。因此,对 self.treeDiameter 的重复分配总是分配给相同的 one 属性。这个属性不是在每个节点上创建的……只是在你调用 find_diameter 的节点上。

我希望插入的评论已经阐明了这个算法是如何工作的。

注意:您自己创建 calculate_left_height 的想法不会这样做:它永远不会改变它作为参数接收的 height 的值,并最终返回它。所以它返回它已经收到的相同值。那显然不会做太多...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。