📅  最后修改于: 2023-12-03 15:13:43.486000             🧑  作者: Mango
二叉搜索树(BST)是一种非常常见的数据结构,它具有以下特点:
在一颗BST中,如果我们想要计算两个节点之间的最短距离,我们需要做些什么呢?
首先一个朴素的想法可能是暴力枚举所有的节点对,计算它们之间的距离,然后找到最小值。
def min_distance(root, p, q):
def distance(node, target):
if node is None:
return float('inf')
if node == target:
return 0
if node.val > target.val:
return distance(node.left, target) + 1
if node.val < target.val:
return distance(node.right, target) + 1
min_dis = float('inf')
for node in [p, q]:
other = q if node == p else p
dis = distance(root, node) + distance(root, other)
min_dis = min(min_dis, dis)
return min_dis
这种方法的时间复杂度很高,为O(n^2),因为需要枚举所有节点对,计算距离。
上面的方法效率太低,有没有更快的方法呢?
我们可以通过递归寻找BST中两个节点的最近公共祖先(LCA),然后计算两个节点到LCA的距离之和即可。对于递归寻找LCA,我们可以采用二叉树的递归查找算法。
def min_distance(root, p, q):
def find_lca(node, p, q):
if node is None:
return None
if node.val > p.val and node.val > q.val:
return find_lca(node.left, p, q)
elif node.val < p.val and node.val < q.val:
return find_lca(node.right, p, q)
else:
return node
def distance(node, target):
if node is None:
return float('inf')
if node == target:
return 0
if node.val > target.val:
return distance(node.left, target) + 1
if node.val < target.val:
return distance(node.right, target) + 1
lca = find_lca(root, p, q)
return distance(lca, p) + distance(lca, q)
时间复杂度为O(h),其中h为BST的高度,最坏情况下为O(n),因为BST可能退化成链表。
上述方法基于递归,有没有非递归的方法呢?
我们可以考虑利用BST的性质,通过迭代的方式寻找LCA。具体来说,我们从根节点开始,如果当前节点的值比p和q的值都大,说明p和q都在当前节点的左子树里,因此我们继续遍历当前节点的左子树;反之,如果当前节点的值比p和q的值都小,说明p和q都在当前节点的右子树里,因此我们继续遍历当前节点的右子树;否则说明当前节点就是p和q的LCA。
def min_distance(root, p, q):
def distance(node, target):
if node is None:
return float('inf')
if node == target:
return 0
if node.val > target.val:
return distance(node.left, target) + 1
if node.val < target.val:
return distance(node.right, target) + 1
lca = root
while True:
if lca.val > p.val and lca.val > q.val:
lca = lca.left
elif lca.val < p.val and lca.val < q.val:
lca = lca.right
else:
break
return distance(lca, p) + distance(lca, q)
时间复杂度同样为O(h)。
以上三种方法都是比较常见的寻找BST中两个节点之间最短距离的方法。其中迭代寻找LCA的方法比较简洁高效,但需要注意终止循环的条件;而递归寻找LCA的方法比较容易理解,但需要调用函数进行递归,可能会占用较多栈空间。在实际应用中,需要根据具体情况选择合适的方法。