在二进制搜索树中查找第k个最接近的元素

时间:2013-03-31 08:14:02

标签: tree binary-tree binary-search-tree

这是我在采访中提出的一个问题。对于给定的BST,找到第k个最接近的元素。穿越整棵树是不可接受的。解决方案不应该是o(n),并且空间复杂性不是问题。 感谢。

我的尝试 - 遍历树的一个分支以获取可能的元素,然后从这些元素开始遍历分支。

3 个答案:

答案 0 :(得分:1)

首先我们必须找到。 1,首先你必须获得节点(来自BST根目录) 你必须得到它下面和远处k的节点。 你必须得到一个上面是k节点的祖先。 4.你必须得到距离它第k个的节点。 (在同一级别或其他级别)

                                    A(8) 
                                /         \
                              B(6)           C(22)
                           /    \         /  \
                         D(5)    E(7)   F(17) G(26)
                                      /  \      \
                                  (15)H   I(19)     N(29)
                                    /      \
                              (14) K        L(20)

Okie认为树是BST树(A,B,C d不是BST的序列,*认为它们是节点引用以标识节点而不是值*) 我已经附上了一个代表价值观的数字。

再考虑一下。 因为它被宣布为BST树。没有父指针。 *

您获得了树的根A. 给出数字17,并给出k = 2的值。 第17号获得参考(F) 对于k = 2,即从2节点距离获得树的所有节点。  作为F的死者你必须检测K(14)和L(20)  作为F的中心你必须得到节点A.  再次你必须得到节点G(2节点距离)(虽然没有父指针你必须得到它)。

一步一步 1    首先是数字 - > 17得到参考F(你有的根)做一个简单的二进制搜索。

ArrayList get_it( Node root_node, int number) {
    node = root_node; 
    if (node ==null)
        throw new IllegarArgumentException("null root node");
    ArrayList  pathtracker = new ArrayList();
    //is the root node matches 
    pathtracker.add(node);  // fix
    if( node.data=number) // fix
    return pathtracker; 
    while(node !=null) {
        if ( node.data==number){
           return pathtracker;
        }
        if ( node.data >= number ){
            node=node.left;
        }
        else{
            node=node.right;
        }
        pathtracker.add(node);        
    } // end of while loop
    return new ArrayList(); //search failed node is not present.
   // returning empty arrayList
 }

现在我们将使用pathtracker。 这具有从根到此节点的轨道节点。 第0个节点是root,length() - 第1个节点是我们拥有的节点 搜索。

for ( int i = pathtracker.length() - 1 , depth=k ;
         ( depth => 0 && i => 0 ) ; i--,depth-- ){  
    if ( i == pathtracker.length() - 1) {//first case
        printnodeDistancek( pathtracker.get(i), depth);
    }else {
        if( pathtracker.get(i).left ! = pathtracker.get(i+1) ){
            printnodeDistancek( pathtracker.get(i).left, depth);
        }else{
            printnodeDistancek( pathtracker.get(i).right, depth);
        }       
    } // end of else block
} // end of loop

void printnodeDistancek( node n, k) {
    if (node==null)
      return;
    if ( k = 0) {
      print node.data;
      return;
    }
    printnodeDistancek( n.left, k-1);
    printodeDistanceK( node.right, k-1);
}

给出的数字是17(F节点)和 现在如果k = 3,则应该打印N和B.     如果K = 4,则应打印D(5)和E97)

答案 1 :(得分:1)

我想这个问题是关于将BST的第K个最接近的元素找到值V,

注意:除非BST平衡,否则在O(n)时间内不可能做到这一点,

要找到第K个最接近的元素: 到目前为止,我们保持与V最接近的K个整数, 1.访问每个节点(从根开始),我们将节点的值,其前身的值和后继值添加到目前为止看到的最接近的值。 (如果数组已满,我们只将一个值放入接近V的数组中。我们用这个值替换最大的一个)

2.如果当前节点的后继接近V,则选择正确的分支;如果前一个接近,则选择左分支。

3.我们重复,直到没有更多的节点访问(我们得到一片叶子)

4.时间复杂度:O(n ^ 2 * k),如果我们假设k是常数(例如k = 3)并且树是平衡的,则时间复杂度将是:O(log(n)^ 2)

Integer[] closest = new Integer[3]; // initialized with null  
void find_3rd_closest(Node current , int K){

    Node succ = Successor(current);
    Node pred = Predecessor(current);

    insert(closest , current.val , K);
    if (succ != null)
        insert(closest , succ.val , K);
    if (pred != null)
        insert(closest , pred.val , K);

    if (succ != null && pred != null)
        if (Math.abs(pred.val - K) < Math.abs(succ.val - K))
            find_3rd_closest(pred , K);
        else
            find_3rd_closest(succ , K);
    else if (pred != null)
        find_3rd_closest(pred , K);
    else if (succ != null)
        find_3rd_closest(succ , K);
    else
        return;
}

void insert(int[] closest , int val, int K){
    for (int i = 0 ; i < closest.length ; i++){
        if (closest[i] != null && Math.abs(K - val) < Math.abs(K - closest[i])){
            for (int j = i ; i < closest.length - 1 ; i++){
                int temp = closest[i+1];
                closest[i+1] = closest[i];
                closest[i] = temp;
            }
        }
        closest[i] = succ.value;
    }
}

Node Successor(Node current){
    if (current.rightChild == null)
        return null;
    current = current.rightChild;
    while (current.leftChild != null)
        current = current.leftChild;
    return current;
}

Node Predecessor(Node current){
    if (current.leftChild == null)
        return null;
    current = current.leftChild;
    while (current.rigthChild != null)
        current = current.rightChild;
    return current;
}

答案 2 :(得分:0)

我假设两个节点之间的接近程度是由它们之间的边数定义的,并且为了解决模糊性,也假设在相等距离的情况下,父节点最接近然后是右节点然后是左节点。

根节点的第k个最接近的元素将是第k个元素是树的级别顺序遍历。

对于树中的任何节点,我们将从距离一个边缘的节点开始,即其父,右,左,然后距离2边缘,即距离1处的节点的父,右,左等,依此类推。我们将继续计数直到达到k个节点,同时确保我们不计算两个节点。考虑以下伪代码。

KthClosest(Node * node, k)
{
    std::queue<Node *> queue;
    std::map<Node *, bool> mapToCheckIFNodeIsCounted;
    int count = 0;
    queue.push_back(node);
    while(count <k)
     {
       Node* node = queue.pop();
       if(node ->parent != NULL)
       {
          if(mapToCheckIFNodeIsCounted.find(node->parent) ==mapToCheckIFNodeIsCounted.end())
            {
              queue->push_back(node->parent);
              mapToCheckIFNodeIsCounted.insert(std::pair<node->parent,true>);

            }
        }
        if(node -> right != NULL)
        {

           if(mapToCheckIFNodeIsCounted.find(node->right) == mapToCheckIFNodeIsCounted.end())
           {
             queue->push_back(node->right);
            mapToCheckIFNodeIsCounted.insert(std::pair<node->right,true>);
           }
        }
        if(node -> left != NULL)
        {

             if(mapToCheckIFNodeIsCounted.find(node->parent) == mapToCheckIFNodeIsCounted.end())
            {
               queue->push_back(node->left);

               mapToCheckIFNodeIsCounted.insert(std::pair<node->left,true>);
            }
       }
       count++;

    }

   // Kth node is the node in queue after loop has finished fraversing k closest elements

   Node *node = queue.pop();
   print(node->value);



}