📌  相关文章
📜  在给定的二叉树中找到最大的BST子树|套装1

📅  最后修改于: 2021-05-24 21:39:04             🧑  作者: Mango

给定一个二叉树,编写一个函数,该函数返回最大子树的大小,该子树也是一个二叉搜索树(BST)。如果完整的二叉树是BST,则返回整个树的大小。

例子:

Input: 
      5
    /  \
   2    4
 /  \
1    3

Output: 3 
The following subtree is the maximum size BST subtree 
   2  
 /  \
1    3


Input: 
       50
     /    \
  30       60
 /  \     /  \ 
5   20   45    70
              /  \
            65    80
Output: 5
The following subtree is the maximum size BST subtree 
      60
     /  \ 
   45    70
        /  \
      65    80

方法1(简单但效率低下)
从根开始,对树进行有序遍历。对于每个节点N,检查以N为根的子树是否为BST。如果是BST,则返回以N为根的子树的大小。否则,递归左和右子树,并返回左和右子树返回的最大值。

/* 
  See https://www.geeksforgeeks.org/write-a-c-program-to-calculate-size-of-a-tree/ for implementation of size()
  
  See Method 3 of https://www.geeksforgeeks.org/a-program-to-check-if-a-binary-tree-is-bst-or-not/ for
  implementation of isBST() 
  
  max() returns maximum of two integers 
*/   
int largestBST(struct node *root)
{
   if (isBST(root))
     return size(root); 
   else
    return max(largestBST(root->left), largestBST(root->right));
}

时间复杂度:此方法最坏的情况是时间复杂度为O(n ^ 2)。考虑用于最坏情况分析的偏斜树。

方法2(棘手而又高效)
在方法1中,我们以自上而下的方式遍历树,并对每个节点进行BST测试。如果我们以自下而上的方式遍历树,则可以将有关子树的信息传递给父树。父级只能在固定时间(或O(1)时间)内使用传递的信息进行BST测试(针对父级节点)。左子树需要告诉父树是否是BST,还需要在其中传递最大值。这样我们就可以将最大值与父母的数据进行比较,以检查BST属性。同样,右子树需要将最小值传递到树上。子树需要将以下信息传递到树上,以查找最大的BST。
1)子树本身是否是BST(在下面的代码中,is_bst_ref用于此目的)
2)如果子树是其父级的左子树,则其中的最大值。如果它是正确的子树,则其中的最小值。
3)如果此子树是BST,则此子树的大小(在下面的代码中,为此使用maximumBSTtil()的返回值)

max_ref用于将最大值传递到树上,而min_ptr用于将最小值传递给树上。

C++
// C++ program of above approach
#include 
  
using namespace std; 
  
/* A binary tree node has data, 
pointer to left child and a pointer
to right child */
class node 
{ 
    public:
    int data; 
    node* left; 
    node* right; 
      
    /* Constructor that allocates 
    a new node with the given data 
    and NULL left and right pointers. */
    node(int data)
    {
        this->data = data;
        this->left = NULL;
        this->right = NULL;
          
    }
}; 
  
  
int largestBSTUtil(node* node, int *min_ref, int *max_ref, 
                    int *max_size_ref, bool *is_bst_ref); 
  
/* Returns size of the largest BST
subtree in a Binary Tree 
(efficient version). */
int largestBST(node* node) 
{ 
    // Set the initial values for
    // calling largestBSTUtil() 
    int min = INT_MAX; // For minimum value in right subtree 
    int max = INT_MIN; // For maximum value in left subtree 
      
    int max_size = 0; // For size of the largest BST 
    bool is_bst = 0; 
      
    largestBSTUtil(node, &min, &max, 
                    &max_size, &is_bst); 
      
    return max_size; 
} 
  
/* largestBSTUtil() updates *max_size_ref
for the size of the largest BST subtree.
Also, if the tree rooted with node is 
non-empty and a BST, then returns size
of the tree. Otherwise returns 0.*/
int largestBSTUtil(node* node, int *min_ref, int *max_ref, 
                    int *max_size_ref, bool *is_bst_ref) 
{ 
  
    /* Base Case */
    if (node == NULL) 
    { 
        *is_bst_ref = 1; // An empty tree is BST 
        return 0; // Size of the BST is 0 
    } 
      
    int min = INT_MAX; 
      
    /* A flag variable for left subtree property 
        i.e., max(root->left) < root->data */
    bool left_flag = false; 
      
    /* A flag variable for right subtree property 
        i.e., min(root->right) > root->data */
    bool right_flag = false; 
      
    int ls, rs; // To store sizes of left and right subtrees 
      
    /* Following tasks are done by 
    recursive call for left subtree 
        a) Get the maximum value in left 
        subtree (Stored in *max_ref) 
        b) Check whether Left Subtree is 
        BST or not (Stored in *is_bst_ref) 
        c) Get the size of maximum size BST 
        in left subtree (updates *max_size) */
    *max_ref = INT_MIN; 
    ls = largestBSTUtil(node->left, min_ref, max_ref,
                        max_size_ref, is_bst_ref); 
    if (*is_bst_ref == 1 && node->data > *max_ref) 
        left_flag = true; 
      
    /* Before updating *min_ref, store the min
    value in left subtree. So that we have the
    correct minimum value for this subtree */
    min = *min_ref; 
      
    /* The following recursive call
    does similar (similar to left subtree) 
    task for right subtree */
    *min_ref = INT_MAX; 
    rs = largestBSTUtil(node->right, min_ref, 
                        max_ref, max_size_ref, is_bst_ref); 
    if (*is_bst_ref == 1 && node->data < *min_ref) 
        right_flag = true; 
      
    // Update min and max values for 
    // the parent recursive calls 
    if (min < *min_ref) 
        *min_ref = min; 
    if (node->data < *min_ref) // For leaf nodes 
        *min_ref = node->data; 
    if (node->data > *max_ref) 
        *max_ref = node->data; 
      
    /* If both left and right subtrees are BST. 
    And left and right subtree properties hold
    for this node, then this tree is BST. 
    So return the size of this tree */
    if(left_flag && right_flag) 
    { 
        if (ls + rs + 1 > *max_size_ref) 
            *max_size_ref = ls + rs + 1; 
        return ls + rs + 1; 
    } 
    else
    { 
        // Since this subtree is not BST, 
        // set is_bst flag for parent calls 
        *is_bst_ref = 0; 
        return 0; 
    } 
} 
  
/* Driver code*/
int main() 
{ 
        /* Let us construct the following Tree 
            50 
        / \ 
        10 60 
        / \ / \ 
    5 20 55 70 
                / / \ 
            45 65 80 
    */
      
    node *root = new node(50); 
    root->left = new node(10); 
    root->right = new node(60); 
    root->left->left = new node(5); 
    root->left->right = new node(20); 
    root->right->left = new node(55); 
    root->right->left->left = new node(45); 
    root->right->right = new node(70); 
    root->right->right->left = new node(65); 
    root->right->right->right = new node(80); 
      
    /* The complete tree is not BST 
    as 45 is in right subtree of 50. 
    The following subtree is the largest BST 
            60 
        / \ 
        55 70 
    / / \ 
    45 65 80 
    */
    cout<<" Size of the largest BST is "<< largestBST(root); 
  
    return 0; 
} 
  
// This code is contributed by rathbhupendra


C
#include 
#include 
#include 
  
/* A binary tree node has data, pointer to left child
   and a pointer to right child */
struct node
{
    int data;
    struct node* left;
    struct node* right;
};
  
/* Helper function that allocates a new node with the
   given data and NULL left and right pointers. */
struct node* newNode(int data)
{
  struct node* node = (struct node*)
                      malloc(sizeof(struct node));
  node->data = data;
  node->left = NULL;
  node->right = NULL;
  
  return(node);
}
  
int largestBSTUtil(struct node* node, int *min_ref, int *max_ref,
                             int *max_size_ref, bool *is_bst_ref);
  
/* Returns size of the largest BST subtree in a Binary Tree
  (efficient version). */
int largestBST(struct node* node)
{
  // Set the initial values for calling largestBSTUtil()
  int min = INT_MAX;  // For minimum value in right subtree
  int max = INT_MIN;  // For maximum value in left subtree
  
  int max_size = 0;  // For size of the largest BST
  bool is_bst = 0;
  
  largestBSTUtil(node, &min, &max, &max_size, &is_bst);
  
  return max_size;
}
  
/* largestBSTUtil() updates *max_size_ref for the size of the largest BST
   subtree.   Also, if the tree rooted with node is non-empty and a BST,
   then returns size of the tree. Otherwise returns 0.*/
int largestBSTUtil(struct node* node, int *min_ref, int *max_ref,
                            int *max_size_ref, bool *is_bst_ref)
{
  
  /* Base Case */
  if (node == NULL)
  {
     *is_bst_ref = 1; // An empty tree is BST
     return 0;    // Size of the BST is 0
  }
  
  int min = INT_MAX;
  
  /* A flag variable for left subtree property
     i.e., max(root->left) < root->data */
  bool left_flag = false;
  
  /* A flag variable for right subtree property
     i.e., min(root->right) > root->data */
  bool right_flag = false;
  
  int ls, rs; // To store sizes of left and right subtrees
  
  /* Following tasks are done by recursive call for left subtree
    a) Get the maximum value in left subtree (Stored in *max_ref)
    b) Check whether Left Subtree is BST or not (Stored in *is_bst_ref)
    c) Get the size of maximum size BST in left subtree (updates *max_size) */
  *max_ref = INT_MIN;
  ls = largestBSTUtil(node->left, min_ref, max_ref, max_size_ref, is_bst_ref);
  if (*is_bst_ref == 1 && node->data > *max_ref)
     left_flag = true;
  
  /* Before updating *min_ref, store the min value in left subtree. So that we
     have the correct minimum value for this subtree */
  min = *min_ref;
  
  /* The following recursive call does similar (similar to left subtree) 
    task for right subtree */
  *min_ref =  INT_MAX;
  rs = largestBSTUtil(node->right, min_ref, max_ref, max_size_ref, is_bst_ref);
  if (*is_bst_ref == 1 && node->data < *min_ref)
     right_flag = true;
  
  // Update min and max values for the parent recursive calls
  if (min < *min_ref)
     *min_ref = min;
  if (node->data < *min_ref) // For leaf nodes
     *min_ref = node->data;
  if (node->data > *max_ref)
     *max_ref = node->data;
  
  /* If both left and right subtrees are BST. And left and right
     subtree properties hold for this node, then this tree is BST.
     So return the size of this tree */
  if(left_flag && right_flag)
  {
     if (ls + rs + 1 > *max_size_ref)
         *max_size_ref = ls + rs + 1;
     return ls + rs + 1;
  }
  else
  {
    //Since this subtree is not BST, set is_bst flag for parent calls
     *is_bst_ref = 0; 
     return 0;
  }
}
  
/* Driver program to test above functions*/
int main()
{
    /* Let us construct the following Tree
          50
       /      \
     10        60
    /  \       /  \
   5   20    55    70
            /     /  \
          45     65    80
  */
  
  struct node *root = newNode(50);
  root->left        = newNode(10);
  root->right       = newNode(60);
  root->left->left  = newNode(5);
  root->left->right = newNode(20);
  root->right->left  = newNode(55);
  root->right->left->left  = newNode(45);
  root->right->right = newNode(70);
  root->right->right->left = newNode(65);
  root->right->right->right = newNode(80);
  
  /* The complete tree is not BST as 45 is in right subtree of 50.
     The following subtree is the largest BST
        60
      /  \
    55    70
   /     /  \
 45     65    80
  */
  printf(" Size of the largest BST is %d", largestBST(root));
  
  getchar();
  return 0;
}


Java
// Java program to find largest BST subtree in given Binary Tree
  
class Node {
  
    int data;
    Node left, right;
  
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class Value {
  
    int max_size = 0; // for size of largest BST
    boolean is_bst = false;
    int min = Integer.MAX_VALUE;  // For minimum value in right subtree
    int max = Integer.MIN_VALUE;  // For maximum value in left subtree
  
}
  
class BinaryTree {
  
    static Node root;
    Value val = new Value();
  
    /* Returns size of the largest BST subtree in a Binary Tree
     (efficient version). */
    int largestBST(Node node) {
  
        largestBSTUtil(node, val, val, val, val);
  
        return val.max_size;
    }
  
    /* largestBSTUtil() updates *max_size_ref for the size of the largest BST
     subtree.   Also, if the tree rooted with node is non-empty and a BST,
     then returns size of the tree. Otherwise returns 0.*/
    int largestBSTUtil(Node node, Value min_ref, Value max_ref,
            Value max_size_ref, Value is_bst_ref) {
  
        /* Base Case */
        if (node == null) {
            is_bst_ref.is_bst = true; // An empty tree is BST
            return 0;    // Size of the BST is 0
        }
  
        int min = Integer.MAX_VALUE;
  
        /* A flag variable for left subtree property
         i.e., max(root->left) < root->data */
        boolean left_flag = false;
  
        /* A flag variable for right subtree property
         i.e., min(root->right) > root->data */
        boolean right_flag = false;
  
        int ls, rs; // To store sizes of left and right subtrees
  
        /* Following tasks are done by recursive call for left subtree
         a) Get the maximum value in left subtree (Stored in *max_ref)
         b) Check whether Left Subtree is BST or not (Stored in *is_bst_ref)
         c) Get the size of maximum size BST in left subtree (updates *max_size) */
        max_ref.max = Integer.MIN_VALUE;
        ls = largestBSTUtil(node.left, min_ref, max_ref, max_size_ref, is_bst_ref);
        if (is_bst_ref.is_bst == true && node.data > max_ref.max) {
            left_flag = true;
        }
  
        /* Before updating *min_ref, store the min value in left subtree. So that we
         have the correct minimum value for this subtree */
        min = min_ref.min;
  
        /* The following recursive call does similar (similar to left subtree) 
         task for right subtree */
        min_ref.min = Integer.MAX_VALUE;
        rs = largestBSTUtil(node.right, min_ref, max_ref, max_size_ref, is_bst_ref);
        if (is_bst_ref.is_bst == true && node.data < min_ref.min) {
            right_flag = true;
        }
  
        // Update min and max values for the parent recursive calls
        if (min < min_ref.min) {
            min_ref.min = min;
        }
        if (node.data < min_ref.min) // For leaf nodes
        {
            min_ref.min = node.data;
        }
        if (node.data > max_ref.max) {
            max_ref.max = node.data;
        }
  
        /* If both left and right subtrees are BST. And left and right
         subtree properties hold for this node, then this tree is BST.
         So return the size of this tree */
        if (left_flag && right_flag) {
            if (ls + rs + 1 > max_size_ref.max_size) {
                max_size_ref.max_size = ls + rs + 1;
            }
            return ls + rs + 1;
        } else {
            //Since this subtree is not BST, set is_bst flag for parent calls
            is_bst_ref.is_bst = false;
            return 0;
        }
    }
  
    public static void main(String[] args) {
        /* Let us construct the following Tree
                50
             /      \
            10        60
           /  \       /  \
          5   20    55    70
         /     /  \
        45   65    80
         */
  
        BinaryTree tree = new BinaryTree();
        tree.root = new Node(50);
        tree.root.left = new Node(10);
        tree.root.right = new Node(60);
        tree.root.left.left = new Node(5);
        tree.root.left.right = new Node(20);
        tree.root.right.left = new Node(55);
        tree.root.right.left.left = new Node(45);
        tree.root.right.right = new Node(70);
        tree.root.right.right.left = new Node(65);
        tree.root.right.right.right = new Node(80);
  
        /* The complete tree is not BST as 45 is in right subtree of 50.
         The following subtree is the largest BST
             60
            /  \
          55    70
          /     /  \
        45     65   80
        */
        System.out.println("Size of largest BST is " + tree.largestBST(root));
    }
}
  
// This code has been contributed by Mayank Jaiswal


Python3
# Helper function that allocates a new
# node with the given data and NULL left
# and right pointers. 
class newNode: 
  
    # Constructor to create a new node 
    def __init__(self, data): 
        self.data = data 
        self.left = None
        self.right = None
  
# Returns size of the largest BST subtree 
# in a Binary Tree (efficient version). 
def largestBST(node):
      
    # Set the initial values for calling 
    # largestBSTUtil() 
    Min = [999999999999] # For minimum value in     
                         # right subtree 
    Max = [-999999999999] # For maximum value in 
                          # left subtree 
      
    max_size = [0] # For size of the largest BST 
    is_bst = [0]
      
    largestBSTUtil(node, Min, Max, 
                         max_size, is_bst) 
      
    return max_size[0]
  
# largestBSTUtil() updates max_size_ref[0] 
# for the size of the largest BST subtree. 
# Also, if the tree rooted with node is
# non-empty and a BST, then returns size of
# the tree. Otherwise returns 0.
def largestBSTUtil(node, min_ref, max_ref, 
                         max_size_ref, is_bst_ref):
      
    # Base Case 
    if node == None:
        is_bst_ref[0] = 1 # An empty tree is BST 
        return 0 # Size of the BST is 0 
      
    Min = 999999999999
      
    # A flag variable for left subtree property 
    # i.e., max(root.left) < root.data 
    left_flag = False
      
    # A flag variable for right subtree property 
    # i.e., min(root.right) > root.data 
    right_flag = False
      
    ls, rs = 0, 0    # To store sizes of left and 
                     # right subtrees 
      
    # Following tasks are done by recursive 
    # call for left subtree 
    # a) Get the maximum value in left subtree 
    #   (Stored in max_ref[0]) 
    # b) Check whether Left Subtree is BST or
    #    not (Stored in is_bst_ref[0]) 
    # c) Get the size of maximum size BST in 
    #    left subtree (updates max_size[0]) 
    max_ref[0] = -999999999999
    ls = largestBSTUtil(node.left, min_ref, max_ref, 
                           max_size_ref, is_bst_ref) 
    if is_bst_ref[0] == 1 and node.data > max_ref[0]: 
        left_flag = True
      
    # Before updating min_ref[0], store the min
    # value in left subtree. So that we have the  
    # correct minimum value for this subtree 
    Min = min_ref[0]
      
    # The following recursive call does similar  
    # (similar to left subtree) task for right subtree 
    min_ref[0] = 999999999999
    rs = largestBSTUtil(node.right, min_ref, max_ref,
                        max_size_ref, is_bst_ref) 
    if is_bst_ref[0] == 1 and node.data < min_ref[0]: 
        right_flag = True
      
    # Update min and max values for the
    # parent recursive calls 
    if Min < min_ref[0]: 
        min_ref[0] = Min
    if node.data < min_ref[0]: # For leaf nodes 
        min_ref[0] = node.data
    if node.data > max_ref[0]: 
        max_ref[0] = node.data
      
    # If both left and right subtrees are BST.
    # And left and right subtree properties hold 
    # for this node, then this tree is BST. 
    # So return the size of this tree 
    if left_flag and right_flag:
        if ls + rs + 1 > max_size_ref[0]: 
            max_size_ref[0] = ls + rs + 1
        return ls + rs + 1
    else:
          
        # Since this subtree is not BST, set is_bst 
        # flag for parent calls is_bst_ref[0] = 0; 
        return 0
  
# Driver Code
if __name__ == '__main__':
      
    # Let us construct the following Tree 
    #     50 
    # /     \ 
    # 10     60 
    # / \     / \ 
    # 5 20 55 70 
    #         /     / \ 
    #     45     65 80
    root = newNode(50) 
    root.left     = newNode(10) 
    root.right     = newNode(60) 
    root.left.left = newNode(5) 
    root.left.right = newNode(20) 
    root.right.left = newNode(55)
    root.right.left.left = newNode(45) 
    root.right.right = newNode(70)
    root.right.right.left = newNode(65) 
    root.right.right.right = newNode(80)
  
# The complete tree is not BST as 45 is in 
# right subtree of 50. The following subtree
# is the largest BST 
#     60 
# / \ 
# 55     70 
# /     / \ 
# 45     65 80 
  
print("Size of the largest BST is", 
                  largestBST(root))
                    
# This code is contributed by PranchalK


C#
using System;
  
// C# program to find largest BST subtree in given Binary Tree 
  
public class Node
{
  
    public int data;
    public Node left, right;
  
    public Node(int d)
    {
        data = d;
        left = right = null;
    }
}
  
public class Value
{
  
    public int max_size = 0; // for size of largest BST
    public bool is_bst = false;
    public int min = int.MaxValue; // For minimum value in right subtree
    public int max = int.MinValue; // For maximum value in left subtree
  
}
  
public class BinaryTree
{
  
    public static Node root;
    public Value val = new Value();
  
    /* Returns size of the largest BST subtree in a Binary Tree 
     (efficient version). */
    public virtual int largestBST(Node node)
    {
  
        largestBSTUtil(node, val, val, val, val);
  
        return val.max_size;
    }
  
    /* largestBSTUtil() updates *max_size_ref for the size of the largest BST 
     subtree.   Also, if the tree rooted with node is non-empty and a BST, 
     then returns size of the tree. Otherwise returns 0.*/
    public virtual int largestBSTUtil(Node node, Value min_ref, Value max_ref, Value max_size_ref, Value is_bst_ref)
    {
  
        /* Base Case */
        if (node == null)
        {
            is_bst_ref.is_bst = true; // An empty tree is BST
            return 0; // Size of the BST is 0
        }
  
        int min = int.MaxValue;
  
        /* A flag variable for left subtree property 
         i.e., max(root->left) < root->data */
        bool left_flag = false;
  
        /* A flag variable for right subtree property 
         i.e., min(root->right) > root->data */
        bool right_flag = false;
  
        int ls, rs; // To store sizes of left and right subtrees
  
        /* Following tasks are done by recursive call for left subtree 
         a) Get the maximum value in left subtree (Stored in *max_ref) 
         b) Check whether Left Subtree is BST or not (Stored in *is_bst_ref) 
         c) Get the size of maximum size BST in left subtree (updates *max_size) */
        max_ref.max = int.MinValue;
        ls = largestBSTUtil(node.left, min_ref, max_ref, max_size_ref, is_bst_ref);
        if (is_bst_ref.is_bst == true && node.data > max_ref.max)
        {
            left_flag = true;
        }
  
        /* Before updating *min_ref, store the min value in left subtree. So that we 
         have the correct minimum value for this subtree */
        min = min_ref.min;
  
        /* The following recursive call does similar (similar to left subtree)  
         task for right subtree */
        min_ref.min = int.MaxValue;
        rs = largestBSTUtil(node.right, min_ref, max_ref, max_size_ref, is_bst_ref);
        if (is_bst_ref.is_bst == true && node.data < min_ref.min)
        {
            right_flag = true;
        }
  
        // Update min and max values for the parent recursive calls 
        if (min < min_ref.min)
        {
            min_ref.min = min;
        }
        if (node.data < min_ref.min) // For leaf nodes
        {
            min_ref.min = node.data;
        }
        if (node.data > max_ref.max)
        {
            max_ref.max = node.data;
        }
  
        /* If both left and right subtrees are BST. And left and right 
         subtree properties hold for this node, then this tree is BST. 
         So return the size of this tree */
        if (left_flag && right_flag)
        {
            if (ls + rs + 1 > max_size_ref.max_size)
            {
                max_size_ref.max_size = ls + rs + 1;
            }
            return ls + rs + 1;
        }
        else
        {
            //Since this subtree is not BST, set is_bst flag for parent calls 
            is_bst_ref.is_bst = false;
            return 0;
        }
    }
  
    public static void Main(string[] args)
    {
        /* Let us construct the following Tree 
                50 
             /      \ 
            10        60 
           /  \       /  \ 
          5   20    55    70 
         /     /  \ 
        45   65    80 
         */
  
        BinaryTree tree = new BinaryTree();
        BinaryTree.root = new Node(50);
        BinaryTree.root.left = new Node(10);
        BinaryTree.root.right = new Node(60);
        BinaryTree.root.left.left = new Node(5);
        BinaryTree.root.left.right = new Node(20);
        BinaryTree.root.right.left = new Node(55);
        BinaryTree.root.right.left.left = new Node(45);
        BinaryTree.root.right.right = new Node(70);
        BinaryTree.root.right.right.left = new Node(65);
        BinaryTree.root.right.right.right = new Node(80);
  
        /* The complete tree is not BST as 45 is in right subtree of 50. 
         The following subtree is the largest BST 
             60 
            /  \ 
          55    70 
          /     /  \ 
        45     65   80 
        */
        Console.WriteLine("Size of largest BST is " + tree.largestBST(root));
    }
}
  
  // This code is contributed by Shrikant13


输出:

Size of largest BST is 6

时间复杂度: O(n),其中n是给定二叉树中的节点数。

二叉树中最大的BST |套装2