Java 在二叉搜索树中有效地找到第k个最小元素?

Java 在二叉搜索树中有效地找到第k个最小元素?,java,algorithm,data-structures,binary-search-tree,Java,Algorithm,Data Structures,Binary Search Tree,今天我遇到了下面的面试问题,我提出了下面提到的递归和迭代的解决方案,但不知为什么面试官不高兴。我不知道为什么 给定一个二叉搜索树,找到其中的第k个最小元素 有没有更好的方法可以用递归或迭代的方式解决这个问题 /***************************************************** * * Kth Smallest Recursive * ************************************************

今天我遇到了下面的面试问题,我提出了下面提到的递归和迭代的解决方案,但不知为什么面试官不高兴。我不知道为什么

给定一个二叉搜索树,找到其中的第k个最小元素

有没有更好的方法可以用递归或迭代的方式解决这个问题

  /*****************************************************
   *
   * Kth Smallest Recursive
   *
   ******************************************************/
  public int kthSmallestRecursive(TreeNode root, int k) {
    int count = countNodes(root.left);
    if (k <= count) {
      return kthSmallestRecursive(root.left, k);
    } else if (k > count + 1) {
      return kthSmallestRecursive(root.right, k - 1 - count);
    }

    return root.data;
  }

  public int countNodes(TreeNode n) {
    if (n == null)
      return 0;

    return 1 + countNodes(n.left) + countNodes(n.right);
  }

  /*****************************************************
   *
   * Kth Smallest Iterative
   *
   ******************************************************/

  public int kthSmallestIterative(TreeNode root, int k) {
    Stack<TreeNode> st = new Stack<>();

    while (root != null) {
      st.push(root);
      root = root.left;
    }

    while (k != 0) {
      TreeNode n = st.pop();
      k--;
      if (k == 0)
        return n.data;
      TreeNode right = n.right;
      while (right != null) {
        st.push(right);
        right = right.left;
      }
    }

    return -1;
  }
/*****************************************************
*
*第k最小递归
*
******************************************************/
公共int-kthsmallestrestrive草书(树根,int-k){
int count=countNodes(root.left);
如果(k计数+1){
返回kthsmallestrestre草书(root.right,k-1-count);
}
返回root.data;
}
公共int countNodes(树节点n){
如果(n==null)
返回0;
返回1+countNodes(n.left)+countNodes(n.right);
}
/*****************************************************
*
*第k最小迭代法
*
******************************************************/
公共int KTHSMALLISTIERATIVE(树根,int k){
Stack st=新堆栈();
while(root!=null){
圣推(根);
root=root.left;
}
while(k!=0){
TreeNode n=圣波普();
k--;
如果(k==0)
返回n.data;
树节点右=n.右;
while(右!=null){
圣普什(右);
右=右。左;
}
}
返回-1;
}
我提到上述两种解决方案的复杂性都是O(节点深度),即O(logn)


我的迭代版本需要额外的空间。有没有什么方法可以在没有额外空间的情况下完成它?

首先,我怀疑它是否需要O(logn)。对于一般的二叉搜索树,它至少是O(n)

对于香草bst,您可以进行迭代或递归,这两种方法都是模拟相同的ignorer遍历过程,具有最差的时间复杂度O(n)和空间复杂度O(logn)(注意,即使递归解决方案也可以从堆栈中获取O(logn)空间)

但是,如果可以稍微更改数据结构,则可以加快速度或使用更少的空间:

  • 如果使用二元搜索树,每个节点记录下的总节点数,则可以将其视为排序数组,并使用O(logn)时间和O(1)空间到达第k个元素

  • 如果使用二进制搜索树,且每个节点都包含父指针和状态指示器,则可以使用与普通解决方案相同的方式遍历该树。在路上,您可以标记节点是否为a。未通过2。其左节点已遍历3。已遍历两个节点。然后你可以在O(n)时间和O(1)空间中完成

  • public int printInorder(节点,int k)
    { 
    
    如果(node==null | | k,你肯定比logn做得更好。他们提到了什么具体的事情吗?你怎么知道他是否不高兴?仅仅一次调用countNodes需要多长时间?计算树中的所有节点(或树中的一半节点)需要多长时间?不是O(logn)。此外,您不必要地多次查看同一个节点-您对它们进行计数,然后递归,然后再次计数,然后递归,等等。您所需要的只是按序遍历中的第k个元素。您的迭代版本似乎正在这样做。递归版本效率不高。@Dukeling所以我的迭代版本仅在重新执行时才有效草书一个有问题,对吗?因为我多次检查相同的节点,你能帮我理解为什么它不是O(logn).第三个选项怎么样?我们不能改变数据结构,需要找到它的原样,那么以最佳方式递归和迭代的复杂性是什么?嗨,john。上面提到了两个选项:对于香草bst,这是我们能做的最好的。嗨,Nicholas,这是为了查找某个元素,而不是第k个最大或最小的元素。B但到目前为止,我的递归解是o(n^2)时间复杂度,对吗?o(1)空间复杂度?@john是的。抱歉这个错误。在最坏的情况下,你的解会取o(n2),而o(1)空间复杂度。我的观点是正确的。@john:
    我的递归解[有…]o(1)空间复杂度?
    只有当你忽略o(n)时才可以调用堆栈以保留需要重新访问的节点(如果需要)。
     public int printInorder(Node node, int k) 
        { 
            if (node == null || k <= 0) //Stop traversing once you found the k-th smallest element
                return k; 
    
            /* first recur on left child */
            k = printInorder(node.left, k); 
    
            k--;
            if(k == 0) {  
                System.out.print(node.key);
            }
    
            /* now recur on right child */
            return printInorder(node.right, k);
        }