543. 二叉树的直径_二叉树的直径

543. 二叉树的直径

Ok, so today we are going to poke around yet another algorithm involving binary trees! (and I promise it’s still fun)

好的,所以今天我们要讨论另一种涉及二叉树的算法! (我保证它仍然很有趣)

So given a binary tree like this:

因此,给定这样的二叉树:

What is the diameter of the tree?

树的直径是多少?

Well, actually it’s quite simple, it’s basically the longest node-pair distance in the tree.

好吧,实际上这很简单, 它基本上是树中最长的节点对距离。

For example the distance between node 0 and 1 is just 1. The distance between node 4 and 0 is 2. All you have to do is imagine yourself grabbing a node in each of your hand, and stretch them into a straight line, the length of the line is the distance between the two nodes.

例如,节点0与1之间的距离仅为1。节点4与0之间的距离为2。您所要做的就是想象自己抓住每只手中的一个节点,并将它们拉伸成一条直线,长度线的长度是两个节点之间的距离。

So what is the longest distance, the diameter, for this tree then? This tree is small enough that you can just eyeball it: it’s the distance between node 2 and node 6, and the distance is 5:

那么,这棵树的最长距离,直径是多少? 这棵树足够小,您只需看一下即可:它是节点2与节点6之间的距离,距离为5:

Image for post

The above picture is the original tree, re-pivoted to have node 2 be the root, and you can see the distance is clearly longest from 2 to 6.

上面的图片是原始的树,重新旋转后以节点2为根,您可以看到距离显然是从2到6最长。

So how do we go about finding the diameter then?

那么我们该如何找到直径呢?

Again first suspect is a recursion, we first recursively traverse through the tree, at each node, find the diameter of the left child and the right child, then add them up to get the diameter of the root. Let see if this works!! (it doesn’t)

同样,第一个可疑对象是递归,我们首先在每个节点上递归地遍历树,找到左子代和右子代的直径,然后将它们加起来得到根的直径。 让我们看看这是否有效!! (没有)

This is my tree:

这是我的树:

class Node:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
tree1 = Node(0)
tree1.left = Node(1)
tree1.right = Node(2)
tree1.left.left = Node(3)
tree1.left.right = Node(4)
tree1.left.left.left = Node(5)
tree1.left.left.left.left = Node(6)

This is my first try:

这是我的第一次尝试:

def find_diameter(tree):
if tree is None:
return None
if tree.left is None and tree.right is None:
return 0
left_diameter = find_diameter(tree.left)
right_diameter = find_diameter(tree.right)
diameter = (left_diameter + 1
if left_diameter is not None
else 0) + \
(right_diameter + 1
if right_diameter is not None
else 0)
return diameter>>> print(find_diameter(tree1))
6

Hmm, isn’t it supposed to be 5?

嗯,不是应该是5吗?

Well it’s not surprising, in the algorithm, we are finding the diameter of the children each time, so in reality we are counting every edge in the tree…

嗯,这并不奇怪,在算法中,我们每次都找到孩子的直径,因此实际上我们在计算树中的每个边。

This won’t work:

这行不通:

diameter = (left_diameter + 1
if left_diameter is not None
else 0) + \
(right_diameter + 1
if right_diameter is not None
else 0)

Because it’s adding up the diameters of the left child and the right child. What we need, is the left child’s maximum length and the right child’s maximum length, let’s modify the algorithm:

因为它将左孩子和右孩子的直径加起来。 我们需要的是左孩子的最大长度和右孩子的最大长度,让我们修改算法:

def find_diameter(tree):
if tree is None:
return None
if tree.left is None and tree.right is None:
return 0
left_length = find_diameter(tree.left)
right_length = find_diameter(tree.right)
diameter = max((left_length + 1
if left_length is not None
else 0),
(right_length + 1
if right_length is not None
else 0))
return diameter

We have replaced “addition” with “max”, does it work now?

我们已经用“ max”代替了“ addition”,现在可以使用吗?

>>> print(find_diameter(tree1))
4

Nope, it returned the maximum length from the root… but what we need is the maximum length of the left child of the root plus the right child of the root.

不,它从根返回了最大长度…但是我们需要的是根的左子项加上根的右子项的最大长度。

We can hack this by calling find_diameter on the left child and the right child of the root and add them up, but it still won’t work. Why? Because the diameter might not be passing through the root!

我们可以通过在根的左子节点和右子节点上调用find_diameter并将它们加起来来破解它,但是仍然无法正常工作。 为什么? 因为直径可能没有穿过根部!

As an example:

举个例子:

Image for post

Clearly this new tree’s diameter goes from node 6 to 5, 3, 1, 4, 7, 8, 9, 10, 11, and its length is 9.

显然,这棵新树的直径从节点6变为5、3、1、4、7、8、9、10、11,其长度为9。

State variable to the rescue!!

状态变量来解救!!

What we can do to solve the problem is by passing in a “global_diameter” state variable to keep track of the longest diameter at each node:

解决问题的办法是传入“ global_diameter”状态变量,以跟踪每个节点的最长直径:

def find_diameter(tree, global_diameter):
if tree is None:
return None
if tree.left is None and tree.right is None:
return 0 # calculate maximum distance of left child and right child
left_length = find_diameter(tree.left, global_diameter)
right_length = find_diameter(tree.right, global_diameter) # calculate diameter of current node
diameter = (left_length + 1
if left_length is not None
else 0) + \
(right_length + 1
if right_length is not None
else 0) # update global_diameter to the maximum local diameter
global_diameter[0] = max(global_diameter[0], diameter) # calculate the max length of current node
# so we can return it
max_length = max((left_length + 1
if left_length is not None
else 0),
(right_length + 1
if right_length is not None
else 0))
return max_length
def entry_find_diameter(tree):
global_diameter = [0]
find_diameter(tree, global_diameter)
return global_diameter[0]

In this new version, we calculate the diameter at each node and update global_diameter to be the maximum found, and return the maximum length at each node for each iteration (See Longest Chain in a Binary Tree for another story on this topic).

在这个新版本中,我们计算每个节点的直径,并将global_diameter更新为找到的最大值,并为每次迭代返回每个节点的最大长度(有关此主题的另一个故事,请参见二叉树中的最长链 )。

Let’s test it out:

让我们测试一下:

>>> print(entry_find_diameter(tree1))
5

Works!

作品!

tree2 = Node(0)
tree2.left = Node(1)
tree2.right = Node(2)
tree2.left.left = Node(3)
tree2.left.right = Node(4, left=Node(7, left=Node(8, left=Node(9, left=Node(10, left=Node(11))))))
tree2.left.left.left = Node(5)
tree2.left.left.left.left = Node(6)
>>> print(entry_find_diameter(tree2))
9

Works again!

再次工作!

翻译自: https://medium.com/@aphria/diameter-of-a-binary-tree-ff15e10eafd4

543. 二叉树的直径

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值