📜  BST中的第二大元素(1)

📅  最后修改于: 2023-12-03 15:13:43.531000             🧑  作者: Mango

BST中的第二大元素

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

  • 每个节点最多有两个子节点;
  • 左子树中的节点值都小于根节点值;
  • 右子树中的节点值都大于根节点值;
  • 每个子树都是BST。

在BST中,所有元素都有一个唯一的后继元素,也就是其右子树中最小的元素。而题目要求的第二大元素,则是BST中比最大元素小的最大元素。接下来,我们将介绍如何找到BST中的第二大元素。

方法一:中序遍历

因为BST中的元素按照大小顺序排列,因此对BST进行中序遍历(Inorder Traversal)可以得到一个从小到大排列的数组。而第二大的元素则是倒数第二个元素。下面是一个中序遍历的实现:

public int findSecondMax(TreeNode root) {

  if (root == null) {
    return -1; // BST中没有元素
  }
  
  List<Integer> inorder = new ArrayList<>();
  inorderTraversal(root, inorder);
  
  if (inorder.size() < 2) {
    return -1; // BST中只有一个元素
  }
  
  return inorder.get(inorder.size() - 2);
}

private void inorderTraversal(TreeNode node, List<Integer> inorder) {

  if (node == null) {
    return;
  }
  
  inorderTraversal(node.left, inorder);
  inorder.add(node.val);
  inorderTraversal(node.right, inorder);
}

该方法的时间复杂度为$O(n)$,其中$n$为BST中的节点数。空间复杂度为$O(n)$,因为需要把所有节点的值都存储在一个数组中。

方法二:右子树最小节点的父节点

另外一个方法是利用BST中每个节点都有一个唯一的后继元素的特点。我们可以从根节点开始,沿着右子树一直走,直到达到一个没有右子树的节点。这个节点的父节点,则是BST中最大的元素。而它的左子树,则是BST中比最大元素小的所有元素。因此,我们只需要在这个左子树中找到最大的元素,即可得到BST中的第二大元素。下面是一个实现:

public int findSecondMax(TreeNode root) {

  if (root == null) {
    return -1; // BST中没有元素
  }
  
  TreeNode maxNode = root;
  TreeNode secondMaxNode = null;
  
  while (maxNode.right != null) {
    secondMaxNode = maxNode;
    maxNode = maxNode.right;
  }
  
  if (maxNode.left != null) {
    maxNode = maxNode.left;
    while (maxNode.right != null) {
      maxNode = maxNode.right;
    }
    return maxNode.val;
  } else {
    return secondMaxNode == null ? -1 : secondMaxNode.val;
  }
}

该方法的时间复杂度为$O(h)$,其中$h$为BST的高度,即最长的从根节点 到叶节点的路径长度。空间复杂度为$O(1)$,因为只需要保存两个指针。

总结

本文介绍了两种方法来找到BST中的第二大元素。第一种方法是通过中序遍历得到节点值的有序数组来找到第二大的元素,其时间复杂度为$O(n)$,空间复杂度也为$O(n)$。第二种方法则是利用BST中每个节点都有一个唯一的后继元素的特点,从根节点开始沿着右子树一直向下遍历,最终找到最大的元素和它的父节点。如果最大元素左侧有元素,则在这些元素中找到最大的元素即可;如果最大元素左侧没有元素,则父节点即为BST中的第二大元素。该方法的时间复杂度为$O(h)$,空间复杂度为$O(1)$。