Python 关于二叉树最大直径问题的困惑
不知道这是怎么回事Python 关于二叉树最大直径问题的困惑,python,algorithm,binary-tree,depth-first-search,Python,Algorithm,Binary Tree,Depth First Search,不知道这是怎么回事 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_hei
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\u height
中的最后一行。为什么需要返回max(leftTreeDiameter,rightTreeDiameter)+1
我显然不明白,但我知道的是,对于每个currentNode
,我们将继续沿着树的左侧走,同样地,然后对右侧走。如果我们最终没有节点(意思是在我们处于叶节点之前),那么我们返回0,因为我们不想为不存在的节点添加1
除了0之外,似乎唯一要添加任何内容的地方是calculate_height
中的最后一行代码,因为尽管我们正在添加leftTreeDiameter+rightTreeDiameter+1
以获得总直径,但这只可能是因为返回0
和返回最大值(leftTreeDiameter,rightTreeDiameter)+1
正确吗
此外,我还不明白为什么可以为leftTreeDiameter分配self.calculate\u height(currentNode.left)
。我的意思是我想我需要像
def calculate_left_height(self, currentNode, height=0):
if currentNode is None:
return 0
self.calculate_height(currentNode.left, height + 1)
return height
我们每次只在高度上加1。在本例中,我没有执行类似于leftTreeDiameter+=self.calculate_height(currentNode.left)
的操作,而是在每次看到节点时作为参数height+1
传入
但是如果我这样做的话,我需要一个单独的方法来计算正确的高度,在我的find_diameter
方法中,需要递归调用find_diameter
,使用root.left
和root.right
我的逻辑哪里错了?计算高度是如何工作的。我想我在试图找出如何跟踪堆栈时遇到了问题?此代码中使用的名称令人困惑:
leftTreeDiameter
和rightTreeDiameter
不是直径,而是高度
第二,函数calculate_height
有副作用,不是很好。一方面,它返回一个高度,同时指定一个直径。这令人困惑。许多Python程序员希望函数是纯函数,只返回一些东西,而不改变其他任何东西。或者,函数只能改变某些状态而不能返回它。两者兼而有之可能会令人困惑
此外,令人困惑的是,尽管该类被称为TreeNode
,但它的find\u 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
的重复赋值始终是同一个属性。不是在每个节点上都创建此属性。。。就在您调用的节点上查找直径
我希望插入的注释阐明了该算法的工作原理
注意:您自己关于创建
calculate\u left\u height
的想法是行不通的:它从不更改作为参数接收的height
的值,并最终返回该值。因此,它返回与已接收到的值相同的值。这显然没有多大作用……此代码中使用的名称令人困惑:leftTreeDiameter
和rightTreeDiameter
不是直径,而是高度
第二,函数calculate_height
有副作用,不是很好。一方面,它返回一个高度,同时指定一个直径。这令人困惑。许多Python程序员希望函数是纯函数,只返回一些东西,而不改变其他任何东西。或者,函数只能改变某些状态而不能返回它。两者兼而有之可能会令人困惑
此外,令人困惑的是,尽管该类被称为TreeNode
,但它的find\u 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
的重复赋值始终是同一个属性。不是在每个节点上都创建此属性。。。就在您调用的节点上查找直径
我希望插入的注释阐明了该算法的工作原理
注意:您自己关于创建
calculate\u left\u height
的想法是行不通的:它从不更改作为参数接收的height
的值,并最终返回该值。因此,它返回与已接收到的值相同的值。这显然没有多大作用……树的“直径”是多少?我不确定是否能很好地解释它,但在父节点,如果你转到左边的子节点,然后从该子节点转到左边和左边,依此类推,从父节点执行同样的操作,但每次看到一个节点时向右计数,并为父节点添加1。这就是这个问题的直径。如果存在直径大于该直径的子树,则应考虑该直径。这有意义吗?也许一个问题的链接会是最好的…对不起,这是一个在线课程,是付费的,所以我不能简单地提供一个链接,但我认为@trincot已经为我澄清了