Given two binary search trees, write function which tells if two such trees are the same – (i.e. same info in the nodes, same branching to left and right at every node).
Do a breadth- or depth-first search on both trees and check each node for equality as you iterate through.
Try this:
bool bst::isequal1(node *& root1,node *& root2)
{
if(root1==NULL && root2==NULL)
{ return true;}
if( (root1==NULL && root2!=NULL) || (root1!=NULL && root2==NULL) )
{
return false;
}
if( (root1->data) != (root2->data) )
{
return false;
}
return ( isequal1(root1->left,root2->left) &&
isequal1(root1->right,root2->right));
}
Related
I need to find if all paths of a binary tree that can end(which means all paths that starts from the root and end to a node that has only one child or none) have lengths that differ by no more than one.
My working solution work like this: the function longestPath finds the longest path, the function checkLengths traverse all nodes keeping track of the length of the paths and every time a node with only one child or none is found it checks if the difference between the length of the current path and the length of the longest path is more than 1.
This solution has complexity O(2n) because at worst every node has to be visited twice, once for the longestPath function and once for the lengthCheck function. I would like to improve the solution to O(n) but I'm having an hard time figuring out how to do so.
Edit: my solution is still O(n) but I would like to optimize it to find the solution by visiting each node only once and not twice.
int lengthCheckFlag=1;
int maxLength=-1;
void longestPath(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxLength==-1){
maxLength=currentLength;
}
else{
if(currentLength>maxLength){
maxLength=currentLength;
}
}
}
longestPath(n->left,currentLength+1);
longestPath(n->right,currentLength+1);
}
void checkLengths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr || n->right==nullptr){
if(abs(maxLength-currentLength)>1){
lengthCheckFlag=0;
}
}
checkLengths(n->left,currentLength+1);
checkLengths(n->right,currentLength+1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
longestPath(n,0);
checkLengths(n,0);
return lengthCheckFlag;
}
Code Update:
int maxP=-1;
int minP=-1;
void minmaxPaths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxP==-1){
maxP=currentLength;
minP=currentLength;
}
else{
if(currentLength>maxP){
maxP=currentLength;
}
if(currentLength<minP){
minP=currentLength;
}
}
}
minmaxPaths(n->left,currentLength+1);
minmaxPaths(n->right,currentLength+1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
minmaxPaths(n,0);
if(abs(minP-maxP)<=1){
return true;
}
return false;
}
Some remarks:
O(2n) is the same as O(n)
Your functions use different conditions for identifying the potential end of a path: one uses a && operator (wrong) and the other uses a || operator (correct)
One idea for an alternative algorithm is to make a breadth first traveral. This is interesting, since the constraint really means that all non-perfect nodes (i.e. that have at most one child) must appear in the bottom two levels of the tree.
By consequence, if we find 2 more levels after the first level where we find a non-perfect node, then we have a violation and can stop the traversal.
The down side is that it uses more memory.
Here is how it could be implemented:
int minmaxDepth(Node root) {
if (root == nullptr) {
return 1; // OK
}
std::vector<Node> level, nextLevel;
level.push_back(root);
int minDepth = INT_MAX;
int currDepth = 0;
while (level.size()) {
currDepth++;
nextLevel = {};
for (auto & parent : level) {
if (currDepth < minDepth &&
(parent->left == nullptr || parent->right == nullptr)) {
minDepth = currDepth; // Found a path with minimal length
}
if (parent->left != nullptr) {
nextLevel.push_back(parent->left);
}
if (parent->right != nullptr) {
nextLevel.push_back(parent->right);
}
if (nextLevel.size() && currDepth > minDepth) {
return 0; // Paths have lengths that differ more than 1
}
}
level = nextLevel;
}
return 1; // All nodes were visited: no violation found
}
There is no need to pre-compute the longest path. Compute all path lengths and on the fly,
store the first length,
if some other length differs by more than one, you are done;
else store the differing length, and if any other length differs from the two stored ones, you are done.
I have question on whether my analysis of runtime and space for algorithm that determine whether a tree S contains a subtree that is exactly the same tree as other tree T My code is as follows:
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null) return subRoot == null;
return isSameTree(root, subRoot) ||
isSubtree(root.left, subRoot) ||
isSubtree(root.right, subRoot);
}
public boolean isSameTree(TreeNode root, TreeNode subRoot) {
if(root == null) return subRoot == null;
if(subRoot == null) return false;
return root.val == subRoot.val &&
isSameTree(root.left, subRoot.left) && isSameTree(root.right, subRoot.right);
}
}
I think the time is O(S * min(S, T)) where S and T are total number of node of tree s and t respectively, and space is O(max(S, T)). I got the time because we are performing dfs on every node of tree s to determine whether it is the same as tree t, and each dfs takes minimum of node of s and t, and space is because our recursion call stack can at most contain minimum of two tree's node, if smaller tree hits null case while dfsing with larger tree, we will just return
You don't need to check on subRoot being null as it is invalid that null is subtree of null. So, in that case you can return false. Please use this code for your reference and time
complexity O(mn), where m = |nodes| ∈ root and n = |nodes| ∈ subRoot
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null)
return false;
if (isSameTree(root, subRoot))
return true;
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
}
public boolean isSameTree(TreeNode root, TreeNode subRoot) {
if(root==null || subRoot==null)
return root==subRoot;
return root.val == subRoot.val && isSameTree(root.left, subRoot.left) && isSameTree(root.right, subRoot.right);
}
}
I am a beginner to binary trees and have been working my way through the algorithms book. I have learnt about the various traversal methods of BSTs (pre-order, post order etc).
Could someone please explain how one can traverse a BST to count the number of nodes that are leaves (no children) please?
Many thanks!
Use a recursive method:
For a leaf return 1.
For a non-leaf, return the sum of that method applied to its children.
Example in PHP:
class BST {
public $left; // The substree containing the smaller entries
public $right; // The substree containing the larger entries
public $data; // The value that is stored in the node
}
function countLeafs(BST $b) {
// Test whether children exist ...
if ($b->left || $b->right) {
// ... yes, the left or the right child exists. It's not a leaf.
// Return the sum of calling countLeafs() on all children.
return ($b->left ? countLeafs($b->left) : 0)
+ ($b->right ? countLeafs($b->right) : 0);
} else {
// ... no, it's a leaf
return 1;
}
}
The different traversal methods would lead to different algorithms (although for a simple problem like this, all DFS variants are more or less the same).
I assume that you have a BST which consists of objects of type Node. A node has two fields left and right of type Node, which are the children of the node. If a child is not present, the value of that field is null. The whole tree is referenced by a reference to the root, called root. In java:
class Node {
public Node left;
public Node right;
}
Node root;
A DFS is easiest to implement by recursion: define a method
int numberOfLeafs(Node node)
which returns the number of leafs in the subtree rooted by node. Of course, numberOfLeafs(root) should yield the number of leafs of the whole tree.
As said, it is really artificial to distinguish pre-, in-, and post-order traversal here, but I'm gonna do it anyway:
Pre-order DFS: First deal with the current node, then with the children
int numberOfLeafs(Node node) {
int result = 0;
if (node.left == null && node.right == null)
result += 1;
if (node.left != null)
result += numberOfLeafs(node.left)
if (node.right != null)
result += numberOfLeafs(node.right)
return result;
}
In-order DFS: First deal with the left child, then with the current node, then with the right child
int numberOfLeafs(Node node) {
int result = 0;
if (node.left != null)
result += numberOfLeafs(node.left)
if (node.left == null && node.right == null)
result += 1;
if (node.right != null)
result += numberOfLeafs(node.right)
return result;
}
Post-order DFS: First deal with the children, then with the current node
int numberOfLeafs(Node node) {
int result = 0;
if (node.left != null)
result += numberOfLeafs(node.left)
if (node.right != null)
result += numberOfLeafs(node.right)
if (node.left == null && node.right == null)
result += 1;
return result;
}
For a BFS, you typically use a simple loop with a queue in which you add unvisited vertices. I now assume that I have a class Queue to which I can add nodes at the end and take nodes from the front:
Queue queue = new Queue();
queue.add(root);
int numberOfLeafs = 0;
while (!queue.empty) {
// take an unhandled node from the queue
Node node = queue.take();
if (node.left == null && node.right == null)
numberOfLeafs += 1;
if (node.left != null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
try this
int countLeafNodes(BTNode node) {
if (node == null)
return 0;
if (node.getLeftChild() == null && node.getRightChild() == null
&& node.getParent() != null)//this is a leaf, no left or right child
return 1;
else
return countLeafNodes(node.getLeftChild())
+ countLeafNodes(node.getRightChild());
}
which recursively counts leaf nodes for left and right sub trees and returns the total count
I'm trying this question for sometime but couldn't figure out the algorithm. My preference is to do it iteratively. Till now, I've figure out something but not sure on some point.
Currently, My algorithm looks like:
First traverse the tree to find the node
While traversing the tree, keep track of the previous node.
if you find the node, check if left child is present then that is successor return.
if left child is not present then check if right child is present the that is successor and return.
if the node(is left to the parent) and don't have left or right child then we've saved the prev node earlier then either prev or prev's right child is the successor.
But what if the node we found is in the right to parent and don't have left or right child how to find successor of this node?
May be there are many flaws in this algorithm as still I've not understand all the cases properly. If anyone has any idea or algorithm please share.
Thanks in advance.
when you find a node in preorder, to find its successor is just travesing to its next node.
what I was thinking first is the relationship of a node and its successor's values in pre-oder, but I found that it seems not very clear like the relationship in in-order. I think there is only one step beteen a node and its successor(if exists) : just move on travesing. So I design this algorithm.
my algorithm below is based on preorder travesal, it can run on a binary tree,not only BST.
#define NOT_FOUND -1
#define NEXT 0
#define FOUND 1
struct node {
struct node *p;//parent,but useless here
struct node *l;//left child
struct node *r;//right child
int value;
};
int travese(struct node* bnode, int* flag,int value)
{
if(bnode == NULL)
return 0;
else
{
if(*flag == FOUND)
//when the successor is found,do pruning.
return 1;
else if(*flag == NEXT) {
printf("successor:%d\n",bnode->value);
*flag = FOUND;
return 1;
}
else if(*flag == NOT_FOUND && bnode->value == value)
*flag = NEXT;
travese(bnode->l,flag,value);
travese(bnode->r,flag,value);
}
return 0;
}
and use it by:
int flag = NOT_FOUND;
travese(root,&flag,value);
if(flag == NEXT || flag == NOT_FOUND)
printf("no successor.\n");
EDIT:
turning a recurrence algorithm to a iterative one is not difficult by using a stack like below:
int preorder_travese_with_stack(struct node* bnode, int* flag,int value)
{
if(bnode == NULL)
return 0;
struct stack s;//some kind of implement
push(s,bnode);
while(NotEmpty(s) && *flag) {
struct node *curNode = pop(s);
if(*flag == NEXT) {
printf("successor:%d\n",curNode->value);
*flag = FOUND;
return 1;
}
else if(*flag == NOT_FOUND && curNode->value == value)
*flag = NEXT;
push(s,curNode->r);
push(s,curNode->l);
}
return 0;
}
but according to your comment and original description, I think the one you want is iterative algorithm without a stack.here it is.
After thinking ,searching and trying, I wrote one. When travse the tree iteratively without stack , the parent of a node is not useless any more. In a path, some nodes is visited not only once, and you need to record its direction at that time.
int preorder_travese_without_stack(struct node *root,int value,int *flag)
{
int state=1;
//state: traveral direction on a node
//1 for going down
//2 for going up from its left chlid
//3 for going up from its right child
struct node *cur = root;
while(1) {
if(state == 1) //first visit
{
//common travese:
//printf("%d ",cur->value);
if(cur->value == value && *flag == NOT_FOUND)
*flag = NEXT;
else if (*flag==NEXT) {
*flag = FOUND;
printf("successor:%d\n",cur->value);
break;
}
}
if((state == 1)&&(cur->l!=NULL))
cur = cur->l;
else if((state==1)&&(cur->l==NULL))
{
state = 2;
continue;
}
else if(state==2) {
if(cur->r != NULL ) {
cur=cur->r;
state = 1;
}
else
{
if(cur->p!=NULL)
{
if(cur==cur->p->r)
state = 3;
//else state keeps 2
cur=cur->p;
}
else //cur->p==NULL
{
if(cur->p->r!=NULL)
{
cur=cur->p->r;
state = 1;
}
else
break;
//end up in lchild of root
//because root's rchild is NULL
}
}
continue;
}
else //state ==3
{
if(cur->p!=NULL)
{
if(cur==cur->p->l)
state = 2;
else
state = 3;
cur=cur->p;
continue;
}
else
break;
}
}
}
the usage is the same as the first recurrence one.
If you are confused yet,mostly about the direction of a node , you can draw a tree and draw the path of pre-order traverse on paper,it would help.
I'm not sure there are bugs left in the code,but it works well on the tree below:
0
/ \
1 2
/ \ / \
3 4 5 6
btw,"wirte down pre-order (or else) travese algorithm of a tree both by recurrence and iteration" is a common interview problem, although solving the latter by a stack is permitted.but I think the BST requirement is unnecessary in pre-order travese.
My implementation of the algorithm does not use the key. Therefore it is possible to use it in any kind of binary tree, not only in Binary search trees.
The algorith I used is this:
if given node is not present, return NULL
if node has left child, return left child
if node has right child, return right child
return right child of the closest ancestor whose right child is present and not yet processed
Bellow there is my solution.
TreeNode<ItemType>* CBinaryTree<ItemType>::succesorPreOrder(TreeNode<ItemType> *wStartNode)
{
//if given node is not present, return NULL
if (wStartNode == NULL) return NULL;
/* if node has left child, return left child */
if (wStartNode->left != NULL) return wStartNode->left;
/* if node has right child, return right child */
if (wStartNode->right != NULL) return wStartNode->right;
/* if node isLeaf
return right child of the closest ancestor whose right child is present and not yet processed*/
if (isLeaf(wStartNode)) {
TreeNode<ItemType> *cur = wStartNode;
TreeNode<ItemType> *y = wStartNode->parent;
while (y->right == NULL && y->parent!=NULL){
cur = y;
y = y->parent;
}
while (y != NULL && cur == y->right) {
cur = y;
y = y->parent;
}
return y->right;
}
}
bool CBinaryTree<ItemType>::isLeaf(TreeNode<ItemType> *wStartNode){
if (wStartNode->left == NULL && wStartNode->right == NULL) return true;
else return false;
};
Given a node with the following structure
class Node {
int data,
Node* P1,
Node* p2;
}
We need to determine, if the node represents a Circular Doubly Link List OR a Binary Tree.
In my opinion We need to start traversing the given node in one direction
node = givenNode;
while(node->P1 != null && node->P1 != givenNode)
{
node = node->p1
}
if(node == givenNode) // It means Circular DLL
else if(node == null) // It means Tree
And it would take O(n) time to detect this.
Please suggest if there is any better approach than this.
I suggest you could check if its a doubl-linked list or not with this piece of code:
node = givenNode;
if(givenNode->P1 == null || givenNode->P2 == null)
// It can not be double link list (circular)
else if(givenNode->p1->p2 == givenNode || givenNode->p2->p1 == givenNode)
{
//It is a double linked list
}
else
{
It is not a double linked list
}
And we have O(1) complexity