我在一次采访中被问到这个问题。我以查找所有子树并检查其中任何一个是否为 bst 的天真方法开始了我的回答。在这个过程中,我们将记录到目前为止看到的 max bst 的大小。
还有比这更好的方法吗?
我在一次采访中被问到这个问题。我以查找所有子树并检查其中任何一个是否为 bst 的天真方法开始了我的回答。在这个过程中,我们将记录到目前为止看到的 max bst 的大小。
还有比这更好的方法吗?
如果你这样做怎么办:
一个。从您的一组边缘中选择最低的加权边缘。
湾。仅当添加该边不会破坏您的 bst 约束时才创建树。
C。从边缘集中删除该边缘。
您最终可能会得到几棵树(因为在不满足 bst 约束时丢弃边可能会使您断开原始图),因此只需选择具有更多节点的树。
我认为您的解决方案是这样的:
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;
}
这个网站似乎涵盖了这个问题:Binary Search Tree Checking。具体来说,这里是 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)
);
}
我假设有 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];
}
对二叉树进行按序遍历,如果任何子树是BST,按序遍历会产生一个升序,边走边记录树的大小。当你遇到一个断点时,递归以便使用断点作为根遍历该树,记录它的大小。选择最大的一个。