BST的第二个最大值

时间:2012-07-11 04:03:14

标签: algorithm data-structures language-agnostic binary-search-tree

这是一个面试问题。在BST中找到第二个最大值。

最大元素是BST中最右边的叶子。第二个最大值是其父或其左子。因此解决方案是遍历BST以找到最右边的叶子并检查其父和左子。

有意义吗?

14 个答案:

答案 0 :(得分:29)

不,那是错的。考虑一下这个BST:

        137
       /
      42
       \
        99

这里,第二个到最大值是最大值的左子项的最右边的子项。您的算法需要更新,以便检查最大值的父级,或最大的左子级的最右侧子级。

另请注意,max不一定是最右边的 leaf 节点,它是树右脊椎底部的节点。上面,137不是叶子。

希望这有帮助!

答案 1 :(得分:14)

回想一下,您可以通过修改inorder traversal以相反的顺序列出BST的节点,然后首先浏览正确的子树。这导致了一个简单的算法:

Node rightmost = findRightmostNode(root)
if (rightmost.left != null) {
    return findRightmostNode(rightmost.left)
else{
    return rightmost.parent
}

如果树只有一个元素,它将返回null。

答案 2 :(得分:9)

public static int findSecondLargestValueInBST(Node root)
    {
        int secondMax;
        Node pre = root;
        Node cur = root;
        while (cur.Right != null)
        {
            pre = cur;
            cur = cur.Right;
        }
        if (cur.Left != null)
        {
            cur = cur.Left;
            while (cur.Right != null)
                cur = cur.Right;
            secondMax = cur.Value;
        }
        else
        {
            if (cur == root && pre == root)
                //Only one node in BST
                secondMax = int.MinValue;
            else
                secondMax = pre.Value;
        }
        return secondMax;
    }

答案 3 :(得分:5)

算法可以如下

1. find the largest number in the tree. 

  private static int findLargestValueInTree(Node root) {
    while (root.right != null) {
     root = root.right;
    }
    return root.data;
  }

2. Find the largest number in the tree that is smaller than the number we found in step 1

 public static int findSecondLargest(Node root, int largest, int current) {
   while (root != null) {
    if (root.data < largest) {
      current = root.data;
      root = root.right;
    } else {
      root = root.left;
   }
   }
  return current;
 }

'current'跟踪当前最大数字,该数字小于步骤1中找到的数字

答案 4 :(得分:5)

更简单的迭代方法,时间复杂度 O(logN)和空间复杂度 O(1)

public static void main(String[] args) {    
        BinaryTreeNode result=isBinarySearchTree.secondLargest(rootNode);

            System.out.println(result.data);
        }

        private BinaryTreeNode secondLargest(BinaryTreeNode node) {

            BinaryTreeNode prevNode=null; //2nd largest Element
            BinaryTreeNode currNode=node;
            if(null == currNode)
                return prevNode;

            while(currNode.right != null){
                prevNode=currNode;
                currNode=currNode.right;
            }
            if(currNode.left != null){
                currNode=currNode.left;
                while(currNode.right != null){
                    currNode=currNode.right;
                }
                prevNode=currNode;
            }

            return prevNode;

        }

答案 5 :(得分:1)

一个遍历变体:

   public Tree GetSecondMax(Tree root)
    {
        Tree parentOfMax = null;

        var maxNode = GetMaxNode(root, ref parentOfMax);

        if (maxNode == root || maxnode.left != null)
        {
            // if maximum node is root or have left subtree, then return maximum from left subtree
            return GetMaxNode(maxnode.left, ref parentOfMax);
        }

        // if maximum node is not root, then return parent of maximum node
        return parentOfMax;
    }

    private Tree GetMaxNode(Tree root, ref Tree previousNode)
    {
        if (root == null || root.right == null)
        {
            // The most right element have reached
            return root;
        }

        // we was there
        previousNode = root;

        return GetMaxNode(root.right, ref previousNode);
    }

答案 6 :(得分:1)

int getmax(node *root)
{
    if(root->right == NULL)
    {
        return root->d;
    }
    return getmax(root->right);
}


int secondmax(node *root)
{
    if(root == NULL)
    {
        return -1;
    }

    if(root->right == NULL && root->left != NULL)
    {
        return getmax(root->left);
    }

    if(root->right != NULL)
    {
        if(root->right->right == NULL && root->right->left == NULL)
        {
            return root->d;
        }
    }

    return secondmax(root->right);
}

答案 7 :(得分:1)

考虑以下两种情况,一种非常直观的思考方式。 设第二大节点为S,最大节点为L。

i)S被插入BST&#34;之前&#34;比L. ii)S被插入BST&#34;之后&#34;比L。

对于第一种情况,很明显L是S的右子节点。这是因为除L之外的任何节点都小于S,因此不会放在S的右侧。因此当L是这将是S的合适孩子。

对于第二种情况,在插入S时,L将是BST中最右边的节点。显然,L不会有一个合适的孩子,因为它是最大的孩子。但是,L可以拥有自己的左子树。当插入S时,S将跟随&#34;右路径&#34;直到它遇到L然后向左转到L的左子树。这里,我们知道L左子树中的所有节点都小于S,所以S将是子树中最右边的节点。

答案 8 :(得分:1)

int getSecondLargest(Node root){
    if(root==null)
        return 0;
    Node curr=root;
    Node prev=root;
    //Go to the largest node
    while(curr.right != null){
        prev = curr;
        curr= curr.right;
    }
    //If largest Node has left child, Then largest element of tree with its root as largest.left will be the second largest number.
    if(curr.left == null)
        return prev.data;
    else
        return findLargest(curr.left);
}

int findLargest(Node root){
    // No need toi check for null condition as in getSecondLargest method, its already done.
    Node curr=root;
    //To find largest just keep on going to right child till leaf is encountered.
    while(curr.right != null){
        curr = curr.right;
    }
    return curr.data;
}

答案 9 :(得分:1)

我会通过将树从最大元素转换为最小元素并在达到询问位置时返回值来实现。我实现了第二大值的类似任务。

void BTree::findSecondLargestValueUtil(Node* r, int &c, int &v)
{
    if(r->right) {
        this->findSecondLargestValueUtil(r->right, c, v);
    }

    c++;

    if(c==2) {
        v = r->value;
        return;
    }

    if(r->left) {
        this->findSecondLargestValueUtil(r->left, c, v);
    }
}


int BTree::findSecondLargestValue()
{
    int c = 0;
    int v = -1;

    this->findSecondLargestValueUtil(this->root, c, v);

    return v;
}

答案 10 :(得分:1)

简单的JavaScript实现。

glGetShader*

答案 11 :(得分:1)

你接近正确的答案。

这是我尝试直观的答案。

最大的节点是最右边的节点。

在最右边节点的左侧子树下的任何内容都大于除最右边节点之外的所有元素。因此,这个子树中最大的节点就是答案。

如果没有左子树,则最右边节点的父节点是大于除最右节点之外的所有其他节点的父节点。

答案 12 :(得分:0)

此算法在树上运行一个并返回Item1处的最大项目和Item2处的第二大项目。 排序调用是 O(1),因为它们与树大小无关。 因此总时间复杂度 O(N)空间复杂度 O(log(N))时树是平衡的。

public static Tuple<int, int> SecondLargest(TreeNode<int> node)
{
    int thisValue = node.Value;
    if ((node.Left == null || node.Left.Right == null) && node.Right == null)
    {
        return new Tuple<int, int>(thisValue, -int.MaxValue);
    }
    else if (node.Left == null || node.Left.Right == null)
    {
        Tuple<int, int> right = SecondLargest(node.Right);
        List<int> sortLargest = new List<int>(new int[] { right.Item1, right.Item2, thisValue });
        sortLargest.Sort();
        return new Tuple<int, int>(sortLargest[2], sortLargest[1]);
    }
    else if (node.Right == null)
    {
        Tuple<int, int> left = SecondLargest(node.Left.Right);
        List<int> sortLargest = new List<int>(new int[] { left.Item1, left.Item2, thisValue });
        sortLargest.Sort();
        return new Tuple<int, int>(sortLargest[2], sortLargest[1]);
    }
    else
    {
        Tuple<int, int> left = SecondLargest(node.Left.Right);
        Tuple<int, int> right = SecondLargest(node.Right);
        List<int> sortLargest = new List<int>(new int[] { left.Item1, left.Item2, right.Item1, right.Item2, thisValue });
        sortLargest.Sort();
        return new Tuple<int, int>(sortLargest[4], sortLargest[3]);
    }
}

答案 13 :(得分:0)

这个想法是一直走到右边,直到右边什么都没有。如果有左边,请走,然后一直走到右边。如果左走,答案就是遇到的最后一个节点。否则,答案是遇到的倒数第二个节点。

这是Java中的递归解决方案:

public TreeNode getSecondLargest(TreeNode root) {
    if(root == null || (root.left == null && root.right == null))
        throw new IllegalArgumentException("The tree must have at least two nodes");
    return helper(root, null, false);
}

private TreeNode helper(TreeNode root, TreeNode parent, boolean wentLeft) {
    if(root.right != null) return helper(root.right, root, wentLeft);
    if(root.left != null && !wentLeft) return helper(root.left, root, true);

    if(wentLeft) return root;
    else return parent;
}

时间复杂度为O(lg n)。