【问题标题】:Given a Binary Tree, find the largest subtree which is a Binary Search Tree给定一棵二叉树,找到最大的子树,它是二叉搜索树
【发布时间】:2012-08-30 00:02:00
【问题描述】:

我在一次采访中被问到这个问题。我以查找所有子树并检查其中任何一个是否为 bst 的天真方法开始了我的回答。在这个过程中,我们将记录到目前为止看到的 max bst 的大小。

还有比这更好的方法吗?

【问题讨论】:

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


【解决方案1】:

如果你这样做会怎样:

  1. 反转图表的权重
  2. 以这种方式使用 Kruskal 算法。

一个。从您的一组边中选择最低的增白边。

b.仅当添加该边不会破坏您的 bst 约束时才创建树。

c。从边缘集中移除该边缘。

您最终可能会得到几棵树(由于在不满足 bst 约束时丢弃边可能会使您断开原始图),因此只需选择具有更多节点的树。

【讨论】:

    【解决方案2】:

    我认为你的解决方案是这样的:

    for each subtree of the tree:
        if the subtree is a binary search tree:
            compute its size
            if it is the largest one found so far:
                best = subtree
    return best
    

    这是低效的,因为它为每个子树做 O(n) 工作,并且最多有 n 个子树。

    你可以通过只走整棵树一次来做得更好。

    // Walk the subtree at node. Find the largest subtree that is a binary search tree
    // and return that tree in *result. Also return that subtree's size and the range
    // of values it covers in *size, *min, and *max.
    void
    walk(Node *node, Node **result, size_t *size, Value *min, Value *max)
    {
        Node *result0 = NULL;
        size_t size0 = 0;
        Value min0, max0;
        if (node->left)
            walk(node->left, &result0, &size0, &min0, &max0);
    
        Node *result1 = NULL;
        size_t size1 = 0;
        Value min1, max1;
        if (node->right)
            walk(node->right, &result1, &size1, &min1, &max1);
    
        // If both subtrees are search trees and node->value falls between them,
        // then node is a search tree.
        if (result0 == node->left
            && result1 == node->right
            && (node->left == NULL || max0 <= node->value)
            && (node->right == NULL || node->value <= min1))
        {
            *result = node;
            *size = size0 + 1 + size1;
            *min = node->left == NULL ? node->value : min0;
            *max = node->right == NULL ? node->value : max1;
        } else if (size0 >= size1) {
            *result = result0;
            *size = size0;
            *min = min0;
            *max = max0;
        } else {
            *result = result1;
            *size = size1;
            *min = min1;
            *max = max1;
        }
    }
    
    Node *
    findLargestBinarySearchSubtree(Node *root)
    {
        Node *result;
        size_t size;
        Value min, max;
        walk(root, &result, &size, &min, &max);
        return result;
    }
    

    【讨论】:

    • 我给了 +1,因为这是唯一不是 O(n^2) 且不明显不正确的答案;但是,请注意,此算法仅返回 FULL 子树。最大的 BST 子树可能只是完整子树的一部分。考虑到这一点比较困难,但仍然可以在 O(n) 中完成。见this question
    • 是的,没错。我以通常在编程中的方式解释“子树”,但数学意义上可能是这里的意图,这会使我的答案出错。
    【解决方案3】:

    这个website 似乎涵盖了这个问题:二叉搜索树检查。具体来说,这里是 C++ 解决方案的摘录

    /*   
     Returns true if the given tree is a binary search tree 
     (efficient version). 
    */ 
    int isBST2(struct node* node) { 
      return(isBSTUtil(node, INT_MIN, INT_MAX)); 
    }
    /* 
     Returns true if the given tree is a BST and its 
     values are >= min and <= max. 
    */ 
    int isBSTUtil(struct node* node, int min, int max) { 
      if (node==NULL) return(true);
    
      // false if this node violates the min/max constraint 
      if (node->data<min || node->data>max) return(false);
    
      // otherwise check the subtrees recursively, 
      // tightening the min or max constraint 
      return 
        isBSTUtil(node->left, min, node->data) && 
        isBSTUtil(node->right, node->data+1, max) 
      ); 
    } 
    

    【讨论】:

    • 这个解决方案只是检查给定的树是否是二叉搜索树。我的问题是在二叉树中找到最大的子树,即 BST。
    【解决方案4】:

    我假设有 O(n) 复杂度需要解决。

    bool is_bst(node * cur)
    {
       if (cur == NULL)
         return true;
    
       // if calculated before cur vertex.
       if (hash_set_bst[cur] != -1)
          return hash_set_bst[cur];
    
       int left_value = MIN;
       int right_value = MAX;
       if (cur -> left != NULL)
          left_value = cur -> left -> value;
       if (cur -> right != NULL)
          right_value = cur -> right -> value;
    
       if (cur -> value > left_value && cur -> value < right_value)
       {
          hash_set_bst[cur] = is_bst(cur->left) && is_bst(cur->right);
          return hash_set_bst[cur];
       }
       else
       {
          hash_set_bst[cur] = 0;
          is_bst(cur->left);
          is_bst(cur->right);
          return hash_set_bst[cur];
       }
    }
    

    现在对于每个节点,您知道它是否可以启动 BST。现在您需要计算子树的大小,然后遍历所有节点,如果节点可以启动 BST,则计算出具有标志的最大大小是多少。

    要计算尺寸,您可以执行以下操作:

    int dfs(node * cur)
    {
       if (cur == NULL) return 0;
       size[cur] = 1 + dfs(cur->left) + dfs(cur->right);
       return size[cur];
    }
    

    【讨论】:

      【解决方案5】:

      对二叉树进行按序遍历,如果任意一个子树是BST,按序遍历会产生一个升序,边走边记录树的大小。当你遇到一个断点时,递归以便使用断点作为根遍历该树,记录它的大小。选择最大的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-10
        • 2015-12-20
        • 1970-01-01
        • 1970-01-01
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        • 2013-07-03
        相关资源
        最近更新 更多