This question already has answers here:
How do you validate a binary search tree?
(33 answers)
Closed 8 years ago.
Today I had an interview where I was asked to write a program which takes a Binary Tree and returns true if it is also a Binary Search Tree otherwise false.
My Approach1: Perform an in-order traversal and store the elements in O(n) time. Now scan through the array/list of elements and check if element at ith index is greater than element at (i+1)th index. If such a condition is encountered, return false and break out of the loop. (This takes O(n) time). At the end return true.
But this gentleman wanted me to provide an efficient solution. I tried but I was unsuccessful, because to find if it is a BST I have to check each node.
Moreover he was pointing me to think over recursion.
My Approach 2: A BT is a BST if for any node N N->left is < N and N->right > N , and the in-order successor of left node of N is less than N and the in-order successor of right node of N is greater than N and the left and right subtrees are BSTs.
But this is going to be complicated and running time doesn't seem to be good. Please help if you know any optimal solution.
It's a pretty well-known problem with the following answer:
public boolean isValid(Node root) {
return isValidBST(root, Integer.MIN_VALUE,
Integer.MAX_VALUE);
}
private boolean isValidBST(Node node, int l, int h) {
if(node == null)
return true;
return node.value > l
&& node.value < h
&& isValidBST(node.left, l, node.value)
&& isValidBST(node.right, node.value, h);
}
The recursive call makes sure that subtree nodes are within the range of its ancestors, which is important. The running time complexity will be O(n) since every node is examined once.
The other solution would be to do an inorder traversal and check if the sequence is sorted, especially since you already know that a binary tree is provided as an input.
The answer provided by #Dhruv is a good one. In addition to that here is one another solution that works in O(n) time.
We need to keep track of the previous node in this approach. In each recursive call we check the previous node data with the current node data. If current node data is less than previous we return false
int isBST(node* root) {
static node* prev = NULL;
if(root==NULL)
return 1;
if(!isBST(root->left))
return 0;
if(prev!=NULL && root->data<=prev->data)
return 0;
prev = root;
return isBST(root->right);
}
boolean b = new Sample().isBinarySearchTree(n1, Integer.MIN_VALUE, Integer.MAX_VALUE);
.......
.......
.......
public boolean isBinarySearchTree(TreeNode node, int min, int max){
if(node == null){
return true;
}
boolean left = isBinarySearchTree(node.getLeft(), min, node.getValue());
boolean right = isBinarySearchTree(node.getRight(), node.getValue(), max);
return left && right && (node.getValue()<max) && (node.getValue()>=min);
}
Comments are invited. Thanks.
I think that the second approach is right. The tree can be traversed in a recursive manner. On each iteration lower and upper bounds of current subtree can be stored. If we want to check subtree with root x, and bounds for the subtree are l and h, then all we need is to check that l <= x <= h and to check the left subtree with bounds l and x, and the right one with bounds x and h.
This will have O(n) complexity, because we start from the root and each node is checked only once as root of some subtree. Also, we need O(h) memory for recursive calls, where h is the height of the tree.
There are some examples above using INTEGER.MAX AND MIN
I cant see a reason to pass them and the significance of it,
correct me if I am wrong in anyway or explain me the reason.
More over binary search tree may have objects which are compared by compareTo method or Coperator.. ( hence Integer.MIN and Integer.MAX dont fit on that model)
I am writing a code where it returns true or false
one has to call (root_node,true) and it will return true if it is a bst else false
void boolean isBSt( node root_node, boolean passed_root)
{
if ( node==null){
if ( passed_root)
return false;
// you have passed null pointer as
//root of the tree , since there is no
// valid start point we can throw an exception or return false
return true;
}
if( node.right !=null )
if ( node.right.data <= node.data)
return false;
if ( node.left !=null )
if ! ( node.left.data <= node.data)
return false;
return ( isBST( node.right , false) && isBST( node.left, false ) )
}
Have a look at this solution:
http://preparefortechinterview.blogspot.com/2013/09/am-i-bst.html
It explains different ways and gives you a generic and efficient method too. Hope it helps.
Here is another Solution which uses 2 helper functions to calculate for each node the min and max value in the subtree using the helper function minValue and maxValue
int isBST(struct node* node)
{
if (node == NULL)
return(true);
/* false if the max of the left is > than us */
if (node->left!=NULL && maxValue(node->left) > node->data)
return(false);
/* false if the min of the right is <= than us */
if (node->right!=NULL && minValue(node->right) < node->data)
return(false);
/* false if, recursively, the left or right is not a BST */
if (!isBST(node->left) || !isBST(node->right))
return(false);
/* passing all that, it's a BST */
return(true);
}
Related
The code below passes all test cases where we try to determine if a tree is a valid BST.
public static boolean validateBst(BST tree) {
return isValid(tree, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public static boolean isValid(BST tree, int min, int max) {
if (tree == null) {
return true;
}
if (tree.value < min || tree.value >= max) {
return false;
}
return isValid(tree.left, min, tree.value) && isValid(tree.right, tree.value, max);
}
The code above checks if a tree is a valid BST. The logic is simple, if a tree is null then it is a BST. If the value of the tree is less than the min and greater than the max we return false as it is not a valid BST condition.
The issue I have is when i change the following line:
if (tree.value < min || tree.value >= max) {
return false;
}
To the following
if (tree.value > min && tree.value < max) {
return true
}
The code does not pass all the test cases. This is confusing to me because I feel like both statements are saying the same thing.
The first if statement is saying if the value of the tree/node is less than the min or more than the max then you are not a valid BST and the second statement is saying if your value is within the range of min and max you are a valid bst.
So please help me understand why when i change that line my code does not pass all the test cases.
Is it because the moment i change that line and return true, i would not be checking the rest of the tree?
The code does not pass all the test cases. This is confusing to me because I feel like both statements are saying the same thing.
There are two problems here, the first one can be fixed easily, the latter requires a more extensive code rewrite.
First of all, the negation of x<y is x≥y. Indeed, with x<y we exclude the possibility that x = y, but if we negate the condition, we should allow this case.
Next you can not just return true if the node has a value between min and max. A tree. Indeed: if the node is between the bounds that is good news, but the children of the node can still not be valid binary search trees, and thus we need to recurse on the children.
We can thus write this as:
if(min <= tree.value && tree.value < max){
return isValid(tree.left,min,tree.value) && isValid(tree.right,tree.value,max);
}
return false;
Note that, depending on how you exactly implemented the search tree, you need to alter tree.value < max to tree.value <= max as well. Since in some trees (like balanced ones), both the left and the right subchild sometimes contain equivalent values. This however might not be very important if your search tree only contains distinct values, which usually is the case.
I want to check if binary search tree provided to me is balanced or not.
Since tree already exists in memory, there is no additional storage needed while checking if tree is balanced when traversing through nodes.
So I assume space complexity would be O(1).
Is it correct?
// Definition for binary tree
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null)
return true;
if (getHeight(root) == -1)
return false;
return true;
}
public int getHeight(TreeNode root) {
if (root == null)
return 0;
int left = getHeight(root.left);
int right = getHeight(root.right);
if (left == -1 || right == -1)
return -1;
if (Math.abs(left - right) > 1) {
return -1;
}
return Math.max(left, right) + 1;
}
}
Your algorithm is O(height) space, not O(1) - you need to store 1 recursive function call in memory for every node as you recurse down the tree, and you can never go deeper than O(height) in the tree (before you return and can get rid of the already-fully-processed nodes).
For a tree like:
(Image reference - Wikipedia)
Your calls will go like this:
getHeight(8)
getHeight(3)
getHeight(1)
getHeight(6)
getHeight(4)
getHeight(7)
getHeight(10)
getHeight(14)
getHeight(13)
Here, getHeight(8) calls getHeight(3), which calls getHeight(1) and getHeight(6), etc.
After we've finished calling the function for 1 (returning the result to the call for 3), we don't need to keep that in memory any more, thus the maximum number of calls that we keep in memory is equal to the height of the tree.
It can be done in O(1) space, but it's fairly complicated and really slow (much slower than the O(n) that your solution takes).
The key is that we have a binary search tree, so, given a node, we'd know whether that node is in the left or right subtree of any ancestor node, which we can use to determine the parent of a node.
I may create a separate Q&A going into a bit more details at some point.
Consider a binary search tree, where all keys are unique. Nodes haven't parent pointers.
We have up to n/2 marked nodes.
I can delete all of them at O(n2) time ( using postorder traversal and when encounter a marked node delete each at O(n)). But it is inappropriate.
I need an algorithm to delete all marked nodes at O(n) time.
Thanks.
EDIT After deletion I need to have nodes order unchanged.
EDIT-2 So it should look like I have deleted each marked node using the typical deletion (finding the rightmost node at the left subtree and exchanging it with the node to delete).
There are many ways, but here is one that should be easy to get right, and give you a perfectly balanced tree as a side effect. It requires linear extra space, however.
Create an array of size N minus the number of marked nodes (or N, if you don't know how many are marked and don't want to check it).
Place the elements in order in the array, by inorder traversal, skipping the marked elements. This takes linear time, and stack space proportional to the height of the tree.
Rebuild the tree top-down using the array. The mid element in the array becomes the new root, the mid element of the left subarray its new left child, and the mid element of the right subarray its new right subchild. Repeat recursively. This takes linear time and logarithmic stack space.
Update: forgot to say skipping the marked elements, but that was obvious, right? ;)
I have found how to do it!
We use an inorder traversal.
We check if node need to be deleted before recursive calls of the function.
When we find a node to delete we stand flag toFindMax and searching the rightmost node in the left subtree.
If we encounter another node to delete we push all our variables to the stack and pop them when the node was deleted.
When we find the maximum in the left subtree we save reference to it and to it's parent.
And then, when we recursively return to the initial node to delete, we delete it (exchange it with the maximum).
static class LinearDeletion {
public static Node MIN_VALUE = new Node(Integer.MIN_VALUE);;
boolean toFindMax = false;
Node parentOfMax = null;
Node max = MIN_VALUE;
Stack<Object> stack = new Stack<>();
public void perform(Node x, Node parent) {
if (x.isToDelete) {
stack.push(toFindMax);
stack.push(parentOfMax);
stack.push(max);
toFindMax = true;
parentOfMax = null;
max = MIN_VALUE;
if (x.left != null) {
perform(x.left, x);
}
if (x.left == null) { //deletion of the node
if (parent.left == x) {
parent.left = x.right;
} else {
parent.right = x.right;
}
} else {
if (x.right == null) {
if (parent.left == x) {
parent.left = x.left;
} else {
parent.right = x.left;
}
} else {
x.key = max.key;
x.isToDelete = max.isToDelete;
if (parentOfMax != x) {
parentOfMax.right = max.left;
} else {
x.left = max.left;
}
}
} // end of deletion
max = (Node) stack.pop();
parentOfMax = (Node) stack.pop();
toFindMax = (boolean) stack.pop();
if (toFindMax) { // check if the current node is the maximum
if (x.key > max.key) {
max = x;
parentOfMax = parent;
}
}
if (x.right != null) {
perform(x.right, x);
}
} else {
if (x.left != null) {
perform(x.left, x);
}
if (toFindMax) {
if (x.key > max.key) {
max = x;
parentOfMax = parent;
}
}
if (x.right != null) {
perform(x.right, x);
}
}
}
}
I don't see why a postorder traversal would be O(n2). The reason that deleting a single node is O(n) is that you need to traverse the tree to find the node, which is an O(n) operation. But once you find a node, it can be deleted in O(1) time.* Thus, you can delete all O(n) marked nodes in a single traversal in O(n) time.
* Unless you need to maintain a balanced tree. However, you don't list that as a requirement.
EDIT As #njlarsson correctly points out in his comment, a delete operation is not normally O(1) even after the node is found. However, since the left and right subtrees are being traversed before visiting a node to be deleted, the minimum (or maximum) elements of the subtrees can be obtained at no additional cost during the subtree traversals. This enables an O(1) deletion.
This question already has answers here:
How do you validate a binary search tree?
(33 answers)
Closed 8 years ago.
I wanted to know if a given binary tree is a binary search tree or not.
I don't know How to do that?
The only thing I know is that the inorder traversal of BST will gives you ascending order output.
So, is this the only condition we need to verify or is there anything else we are suppose to check.
In case if there are some other necessary conditions to be checked, What are they? and why those conditions are necessary to be checked? Because, I think, INORDER traversal itself can tell you easily if the given tree is BST or not.
Yes, if inorder traversal of the tree gives you a strictly monotonic list of values that is sufficient to determine that the tree is a BST.
By definition of Binary search tree, if every node of the binary tree satisfy the following conditions then it is a Binary Search Tree:
The left subtree of a node should contain only nodes with keys less than the node’s key
The right subtree of a node should contain only nodes with keys greater than the node’s key
Both the left and right subtrees must also be binary search trees.
All the above conditions are verified if the inorder traversal is in ascending order.
Actually - it is not enough to just do an in order traversal - you also need to verify that each node's value follows the rules of the tree. In the case of a BST, the left child value is less than the node value and the right child value is greater than the node value. Here is a recursive example in Java.
private static boolean isBST(Node current, Comparable more, Comparable less) {
if (current == null)
return true;
if (less != null && current.value.compareTo(less) > 0)
return false;
if (more != null && current.value.compareTo(more) < 0)
return false;
return isBST(current.left, more, current.value) &&
isBST(current.right, current.value, less);
}
public static boolean isBST(BinarySearchTree tree) {
return isBST(tree.getRoot(), null, null);
}
While doing In-Order traversal, we can keep track of previously visited node
Code:
bool isBST(struct node* root)
{
static struct node *prev = NULL;
// traverse the tree in inorder fashion and keep track of prev node
if (root)
{
if (!isBST(root->left))
return false;
// Allows only distinct valued nodes
if (prev != NULL && root->data <= prev->data)
return false;
prev = root;
return isBST(root->right);
}
return true;
}
A simple but elegant recursive solution in Java:
public static boolean isBST(TreeNode node, int leftData, int rightData)
{
if (node == null) return true;
if (node.getData() > leftData || node.getData() <= rightData) return false;
return (isBST(node.left, node.getData(), rightData)
&& isBST(node.right, leftData, node.getData()));
}
The initial call to this function can be something like this:
if (isBST(root, Integer.MAX_VALUE, Integer.MIN_VALUE))
System.out.println("This is a BST.");
else
System.out.println("This is NOT a BST!");
Essentially we keep creating a valid range (starting from [ MIN_VALUE, MAX_VALUE]) and keep shrinking it down foe each node as we go down recursively.
Source: http://exceptional-code.blogspot.com/2011/08/binary-search-trees-primer.html
This question already has answers here:
In Order Successor in Binary Search Tree
(19 answers)
Closed 5 years ago.
The successor of an element in a BST is the element's successor in the sorted order determined by the inorder traversal. Finding the successor when each node has a pointer to its parent node is presented in CLRS's algorithm textbook (Introduction to Algorithms by MIT press).
The idea to find the successor here is - if the right subtree of node x is nonempty, the successor of x is the minimum element in the right subtree. Otherwise, the successor is the lowest ancestor of x whose left child is also an ancestor of x (assuming a node is an ancestor of itself).
Can we find the successor without using the pointer to the parent node?
Sometimes our tree node does not have this pointer. I struggled a couple of hours but cannot write the correct code.
Inspired by Sheldon's solution ,this is the non-recursive version of the solution.
if (right[x] != NIL)
return min(right[x]);
else
{
candidate = NIL;
y = root;
while (y!= x) // y is used as a probe
if (key[x] < key[y])
{
candidate = y;
y = y ->left;
}
else
y = y->right;
}
return candidate;
If candidate == NIL, x is the max in the tree and does not have a successor.
This should work:
TREE-SUCCESSOR(T, x)
if right[x] != NIL
return TREE-MINIMUM(right[x])
else
return FIND-TREE-SUCCESSOR(root[T], x, NIL)
FIND-TREE-SUCCESSOR(y, x, c)
if y = x
return c
if key[x] < key[y]
return FIND-TREE-SUCCESSOR(left[y], x, y)
else
return FIND-TREE-SUCCESSOR(right[y], x, c)
FIND-TREE-SUCCESSOR keeps in c (of candidate) the last node in which we turned left.
I found an elegant solution for in-order successor without parent pointer here -> http://www.geeksforgeeks.org/archives/9999
Idea is
1.If the node has right sub-tree, then its successor is the least element in the right sub-tree
If the node's right sub-tree is empty, then its successor is one of its ancestors, which can be found top-down without parent pointer, with the following algorithm:
let initially current_node be root, succ_node = null;
case1: If the search element is less than current_node, then the current element is a potential successor - place succ_node at the current_node and move the current_node to its left node(because the search element is in the left subtree)
case2: If the search element is greater then current_node, its not a potential successor (How can a lesser element be the successor?). So no need to place the succ_node here, but move the current_node to right.
keep repeating the process until you reach null or the element itself and return the succ_node.
If you don't have access to the pointer to the parent node then you need to know who the father is. If you don't know it, how could you go up in the tree ?
A recursive Java solution could look the following way:
public Integer successor(Integer value) {
Node n = succ(root, value, null);
if (null != n) {
return n.value;
}
return null;
}
private Node succ(Node n, Integer x, Node p) {
if (null == n) {
return null;
}
if (x < n.value) {
return succ(n.left, x, n);
} else if (x > n.value) {
return succ(n.right, x, p);
}
if (null != n.right) {
return min(n.right);
}
return p;
}
As a client we simply pass in the value of the node from which we want to know the successor. Then we start searching from the root until we found the value we were looking for. Now there are two cases:
If the current node has a right child, then the successor the smallest element in the current node's right subtree
Otherwise, it was the node p (parent pointer), which was only updated when we went left within the tree