计算 O(LogN) 中二叉搜索树范围内的节点数

Count number of nodes within range inside Binary Search Tree in O(LogN)

给定一个 BST 和两个整数 'a' 和 'b' (a < b),我们如何在 O(log n)?

我知道在LogN时间内很容易找到a和b的位置,但是不遍历复杂度O(n)怎么计算中间的节点数呢?

想法很简单。

  1. 从根开始遍历BST
  2. 检查每个节点是否在范围内。 如果它在范围内,则计数++。并重现其双children。
  3. 如果当前节点小于范围的低值,则向右递归child,否则向左递归child。

时间复杂度为O(height + number of nodes in range)..

关于为什么不是 O(n) 的问题。

因为我们不是遍历整棵树也就是树中的节点数。我们只是根据parent的数据遍历所需的子树。

伪代码

int findCountInRange(Node root, int a, int b){

    if(root==null)
       return 0;
    if(root->data <= a && root->data >= b)
         return 1 + findCountInRange(root->left, a, b)+findCountInRange(root->right, a, b); 
    else if(root->data < low)
         return findCountInRange(root->right, a, b);
    else 
         return findCountInRange(root->left, a, b);

}

将BST的中序遍历存储在数组中(会排序)。搜索 'a' 和 'b' 将花费 log(n) 时间并获取它们的索引并取差。这将给出 'a' 到 'b' 范围内的节点数。

space 复杂度 O(n)

在二叉搜索树的每个节点中,还要计算树中小于其值的值的数量(或者,对于下面脚注中提到的不同树设计,其左侧的节点子树)。

现在,首先找到包含值 a 的节点。获取已存储在此节点中的小于 a 的值的计数。这一步是 Log(n).

现在找到包含值 b 的节点。获取存储在此节点中的小于 b 的值的计数。这一步也是Log(n).

将这两个计数相减,得到 ab 之间的节点数。此搜索的总复杂度为 2*Log(n) = O(Log(n)).


参见 this video。教授在这里用Splay Trees解释了你的问题。

简单的解决方案:

  • 从根节点开始检查
  • 如果节点落在范围内,则将其加1并递归检查左右child
  • 如果节点不在范围内,则检查范围内的值。如果范围值小于根,那么绝对可能的场景是左子树。否则检查右子树

    这是示例代码。希望它清除。

    if (node == null) {
        return 0;
    } else if (node.data == x && node.data == y) {
        return 1;
    } else if (node.data >= x && node.data <= y) {
        return 1 + nodesWithInRange(node.left, x, y) + nodesWithInRange(node.right, x, y);
    } else if (node.data > x && node.data > y) {
        return nodesWithInRange(node.left, x, y);
    } else {
        return nodesWithInRange(node.right, x, y);
    }
    

时间复杂度:- O(logn)+ O(K)

K是x和y之间的元素个数。

它不是很理想,但在您不想修改二叉树节点定义的情况下很好。