📜  计算 BST 中总和大于 K 的对(1)

📅  最后修改于: 2023-12-03 14:57:26.610000             🧑  作者: Mango

计算 BST 中总和大于 K 的对

二叉搜索树(Binary Search Tree,简称 BST)是一种非常常见的数据结构,它具有以下特点:

  • 每个节点最多只有两个子节点。
  • 左子树中所有节点的值均小于其父节点的值。
  • 右子树中所有节点的值均大于其父节点的值。

在 BST 中,我们可以计算满足总和大于 K 的节点对数。这样的问题在实际工作中也经常出现,比如给定一些页面的访问量,需要找到访问量排名前 K 的页面。

下面给出一个算法,它的时间复杂度为 O(n log n),其中 n 是 BST 中节点的个数。

首先遍历 BST,计算出每个节点的子树节点总和。这个可以通过将 sum 和大小信息保存在节点中来完成:

class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        self.sum = val
        self.size = 1

    def update(self):
        self.size = 1
        self.sum = self.val
        if self.left:
            self.size += self.left.size
            self.sum += self.left.sum
        if self.right:
            self.size += self.right.size
            self.sum += self.right.sum

然后遍历 BST 中的每个节点,计算出大于 K 的节点对数。我们可以使用递归的方式,遍历 BST 中的每个节点,并计算出小于当前节点值的节点数量 cnt 和大于等于当前节点值的节点数量 sz-cnt-1(其中 sz 是 BST 中节点的个数)。如果当前节点的 val + sum(right_child) > K,那么我们就可以把左子树中所有小于当前节点值的节点和右子树中所有大于等于 K-val-sum(right_child) 的节点组成的节点对加入答案。

代码实现如下:

def countPairs(root, K):
    def dfs(node, less, res):
        if not node: return
        # less: 已经经过的链中小于该节点值的节点数量
        # res: 满足条件的节点对数
        if node.val + node.right.sum > K:
            dfs(node.left, less, res)
            dfs(node.right, less+node.left.size+1, res)
        else:
            res[0] += less + node.left.size
            dfs(node.right, less, res)
            dfs(node.left, less, res)
        node.update()

    res = [0]
    dfs(root, 0, res)
    return res[0]

该算法的难点在于理解其正确性,可以通过手动计算几个样例来加深理解。