Space Complexity of generating all possible binary search trees - java

I used the following recursion algorithm to calculate the possible cases of binary search trees given its number of nodes being n
public List<TreeNode> generateTrees(int n) {
if(n == 0){
List<TreeNode> empty = new ArrayList<TreeNode>();
return empty;
}
return recurHelper(1, n);
}
public List<TreeNode> recurHelper(int start, int end){
if(start > end){
TreeNode nan = null;
List<TreeNode> empty = new ArrayList<TreeNode>();
empty.add(nan);
return empty;
}
List<TreeNode> result = new ArrayList<TreeNode>();
for(int i = start; i <= end; i++){
List<TreeNode> left = recurHelper(start, i-1);
List<TreeNode> right = recurHelper(i+1, end);
for(TreeNode leftBranch:left){
for(TreeNode rightBranch:right){
TreeNode tree = new TreeNode(i);
tree.left = leftBranch;
tree.right = rightBranch;
result.add(tree);
}
}
}
return result;
}
I wonder what is the space complexity for the recursion, should it be O(h), where h is the height of the tree?
I do not think so because at each level we are storing a result consisting of O(lG_l) elements, where l stands for the level and G_l stands for the number of possible trees with l nodes.
Then it seems to me that the space complexity of the recursion should be nG_n + ... + 1G_1.

Related

Converted sorted array to a height-balanced binary search tree

I'm solving leetcode problem to convert a sorted integer array to a binary search tree. A height-balanced binary tree is a binary tree in which the depth of the two subtrees of every node never differs by more than one.
Recursive solution is fairly straightforward, but iterative solution seems to be much more complicated. I came up with the following pretty sub-optimal and not that concise implementation:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode() {}
public TreeNode(int val) { this.val = val; }
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
private static int[] leftNode(int[] arr){
return Arrays.copyOfRange(arr, 0, arr.length / 2);
}
private static int[] rightNode(int[] arr){
return Arrays.copyOfRange(arr, arr.length / 2 + 1, arr.length);
}
private static int root(int arr[]){
return arr[arr.length / 2];
}
public static TreeNode sortedArrayToBstIterative(int[] nums){
if(nums == null || nums.length == 0){
return null;
}
TreeNode root = new TreeNode(root(nums));
List<int[]> parts = Arrays.asList(leftNode(nums), rightNode(nums));
List<TreeNode> level = Collections.singletonList(root);
int notVisited = nums.length - 1;
while(notVisited > 0){
List<TreeNode> nextLevel = new ArrayList<>();
List<int[]> nextParts = new ArrayList<>();
Iterator<int[]> iterator = parts.iterator();
for(TreeNode node: level){
int[] left = iterator.hasNext() ? iterator.next() : null;
if(left != null && left.length != 0){
TreeNode leftNode = new TreeNode(root(left));
node.left = leftNode;
nextLevel.add(leftNode);
nextParts.add(leftNode(left));
nextParts.add(rightNode(left));
notVisited--;
}
int[] right = iterator.hasNext() ? iterator.next() : null;
if(right != null && right.length != 0){
TreeNode rightNode = new TreeNode(root(right));
node.right = rightNode;
nextLevel.add(rightNode);
nextParts.add(leftNode(right));
nextParts.add(rightNode(right));
notVisited--;
}
}
parts = nextParts;
level = nextLevel;
}
return root;
}
The solution is basically about splitting the given array into 2 subarrays until all of the elements are used.
It works fine, but the question is if there's another more concise solution to produce height-balanced binary search tree?
Don't write, never commit or publish undocumented code:
In Java, use doc comments.
You create a lot of arrays.
Give using java.util.Arrays.asList() & List.subList(from, to) a try.
As a complete binary tree is balanced enough, that should be easier to construct.

How to create a binary search tree that includes all numbers from 1 to n

Im trying to create a Binary search tree that includes all numbers from 1 to n. an example would be from 1 to 5 would be something like
root: 3
root.left: 2
root.left.left = 1
root.right = 4
root.right.right = 5
This tree happens to be not very balanced, but I would prefer a method that produces as balanced of a tree as possible.
I am trying to create my own data structure for this, so I basically just wrote a Node class:
private class BinaryNode{
int data;
BinaryNode left;
BinaryNode right;
BinaryNode parent;
}
And I planned on having that inside another class, which represents the tree itself. I am stuck finding a good way determine the left/right values appropriately to build the tree, any help is appreciated!
The data on the root node would be (n+1)/2; if you've got a subtree representing the range [i..j], the root of that subtree is (i+j)/2 (using integer arithmetic).
You can build the tree recursively using that fact:
static BinaryNode build(int i, int j) {
if (i > j) return null;
int mid = (i + j) / 2; // Assumes i >= 0.
BinaryNode node = new BinaryNode();
node.data = mid;
node.left = build(i, mid - 1);
if (node.left != null) node.left.parent = node;
node.right = build(mid + 1, j);
if (node.right != null) node.right.parent = node;
return node;
}
Then start the recursive call:
BinaryNode node = build(1, n);
It must be pointed out, however, that such a binary search tree (storing contiguous integers from 1 to n) is useless: you may as well simply use an array, and "search" it using an array index.
public void insert(int id){
Node newNode = new Node(id);
if(root==null){
root = newNode;
return;
}
Node current = root;
Node parent = null;
while(true){
parent = current;
if(id<current.data){
current = current.left;
if(current==null){
parent.left = newNode;
newNode.parent = parent;
return;
}
}else{
current = current.right;
if(current==null){
parent.right = newNode;
newNode.parent = parent;
return;
}
}
}
}
Without recursion insertion of 1 to n numbers.
public static void main(String arg[]){
Solution2 s = new Solution2();
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int i = 1;i <= n;i++){
s.insert(i);
}
}

Iterative Solution to finding if a tree is balanced

So someone posted their solution to this, but I found that it didn't seem to work, I posted this there but I wanted to make it more accessible to others.
The question is in "Cracking the Code Interview" and it is the first tree question, feel free to make other suggestions (or prove me wrong!)
The key here is that it is difficult to keep track of the eventual paths and their heights with one stack.
What I ended up doing is pushing both the left and right child's height on a stack, checking if they are within one of one another, adding one to the max and then pushing that onto the stack after popping the left and right off.
I have commented so I hope it's clear enough
/* Returns true if binary tree with root as root is height-balanced */
boolean isBalanced(Node root) {
if(root == null) return false;
Deque<Integer> heights = new LinkedList<>();
Deque<Node> trail = new LinkedList<>();
trail.push(root);
Node prev = root; //set to root not null to not confuse when root is misisng children
while(!trail.isEmpty()) {
Node curr = trail.peek(); //get the next node to process, peek because we need to maintain trail until we return
//if we just returned from left child
if (curr.left == prev) {
if(curr.right != null) trail.push(curr.right); //if we can go right go
else {
heights.push(-1); //otherwise right height is -1 does not exist and combine heights
if(!combineHeights(heights)) return false;
trail.pop(); //back to parent
}
}
//if we just returned from right child
else if (curr.right == prev) {
if(!combineHeights(heights)) return false;
trail.pop(); //up to parent
}
//this came from a parent, first thing is to visit the left child, or right if no left
else {
if(curr.left != null) trail.push(curr.left);
else {
if (curr.right != null) {
heights.push(-1); //no left so when we combine this node left is 0
trail.push(curr.right); //since we never go left above logic does not go right, so we must here
}
else { //no children set height to 1
heights.push(0);
trail.pop(); //back to parent
}
}
}
prev = curr;
}
return true;
}
//pop both previous heights and make sure they are balanced, if not return false, if so return true and push the greater plus 1
private boolean combineHeights(Deque<Integer> heights) {
int rightHeight = heights.pop();
int leftHeight = heights.pop();
if(Math.abs(leftHeight - rightHeight) > 1) return false;
else heights.push(Math.max(leftHeight, rightHeight) + 1);
return true;
}
So in the end I managed to create an iterative solution which works for all test cases on Leetcode
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public static boolean isBalanced(TreeNode root) {
if (root == null) return true;
Deque<Pair> queue = new LinkedList<>();
queue.offer(new Pair(root, 0));
while (!queue.isEmpty()) {
var curr = queue.poll();
System.out.printf(">>Curr node is %s and curr.lvl is %s", curr.node.val, curr.lvl);
int left = getSubTreeHeight(new Pair(curr.node.left, curr.lvl + 1));
int right = getSubTreeHeight(new Pair(curr.node.right, curr.lvl + 1));
if (Math.abs(left - right) > 1) return false;
if (curr.node.left != null) queue.offer(new Pair(curr.node.left, curr.lvl + 1));
if (curr.node.right != null) queue.offer(new Pair(curr.node.right, curr.lvl + 1));
}
return true;
}
static int getSubTreeHeight(Pair pair) {
if (pair.node == null) {
return pair.lvl -1;
}
Deque<Pair> queue = new LinkedList<>();
queue.offer(pair);
int height = 0;
while (!queue.isEmpty()) {
Pair curr = queue.poll();
System.out.printf("Curr node is %s and curr.lvl is %s", curr.node.val, curr.lvl);
height = curr.lvl;
if (curr.node.left != null) queue.offer(new Pair(curr.node.left, curr.lvl + 1));
if (curr.node.right != null) queue.offer(new Pair(curr.node.right, curr.lvl + 1));
}
return height;
}
public static class Pair {
TreeNode node;
int lvl;
public Pair(TreeNode node, int lvl) {
this.node = node;
this.lvl = lvl;
}
}
}
The original question in the book does not mention the tree being binary. I happen to solve the same question, but coded in Python. So, here is my iterative solution for the problem, for general trees (where the children of a node is stored in a list), in python.
def is_balanced_nonrecursive(self):
stack = [self.root]
levels = [0]
current_min = sys.maxint
current_max = 0
current_level = 0
while len(stack) > 0:
n = stack.pop()
current_level = levels.pop()
for c in n.children:
stack.append(c)
levels.append(current_level + 1)
if len(n.children) == 0:
if current_level < current_min:
current_min = current_level
if current_level > current_max:
current_max = current_level
return current_max - current_min < 2
This is basically a depth first traversal of the tree. We keep a separate stack for the levels (the list levels). If we see any leaf node, we update the current min and current max levels accordingly. The algorithm traverses the whole tree and at the end if max and min levels differ by more than one, then the tree is not balanced.
There are many optimizations possible, like for instance checking whether the difference of min and max is more than one inside the loop, and if that is the case return False immediately.
Some code repetition on this one, but at least it doesn't give me a headache as the recursive ones do:
public boolean isBalanced() {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
int leftLevel = 0;
int rightLevel = 0;
if(this == null) return false;
if(this.left != null)queue.offer(this.left);
while(!queue.isEmpty()) {
int size = queue.size();
for(int i=0; i < size; i++) {
if(queue.peek().left != null) queue.offer(queue.peek().left);
if(queue.peek().right != null) queue.offer(queue.peek().right);
queue.poll();
}
leftLevel++;
}
if(this.right != null) queue.offer(this.right);
while(!queue.isEmpty()) {
int size = queue.size();
for(int i=0; i < size; i++) {
if(queue.peek().left != null) queue.offer(queue.peek().left);
if(queue.peek().right != null) queue.offer(queue.peek().right);
queue.poll();
}
rightLevel++;
}
return Math.abs(leftLevel - rightLevel) < 2;
}

Why the solution for checking the validity of binary tree is not working?

I'm solving a problem to check if a binary tree is valid binary tree. That means the value of the left node of a certain node is smaller and the value of right node is bigger than the node value. The program uses a recursive method to perform the check and return boolean value to determine the validity of the tree. I provided the code as following,
class Node {
Node left;
Node right;
int data;
public Node(int data_ ){
this.data = data_;
}
}
public class myTest{
private static List<Integer> lis = new ArrayList<Integer>();
public static List<Integer> inOrder(Node root){
if (root != null){
inOrder(root.left);
lis.add(root.data);
System.out.println( root.data );
inOrder(root.right);
}
return lis;
}
public static boolean isBST( Node root, int min, int max ){
if (root == null )
return true;
return ( root.data >= min)
&& ( root.data <= max )
&& isBST(root.left, min, root.data)
&& isBST( root.right, root.data, max );
}
public static void main(String[] args){
// form the bst
Node root = new Node(5);
root.left = new Node(3);
root.right = new Node(7);
root.left.left = new Node(1);
root.left.right = new Node(2);
root.right.left = new Node(6);
root.right.right = new Node(9);
// get the max and min value from the tree
int max = 0;
int min = 0;
if (root != null ){
List<Integer> li = inOrder(root);
min = li.get(0);
max = li.get( li.size() -1 );
}
// determine the validity
boolean bol_ = isBST(root, min, max );
if ( bol_)
System.out.println("valid BST ");
else
System.out.println("Not valid BST ");
}
}
The provided test tree is valid but the program tells it isn't. What is the issue inside that I'm not seeing ? Besides, what will be the edge cases to improve the code ? Say, do I need to check if all the values inside the tree are distinct integer and how to do that ?
As #Thomas pointed out, your tree is not a valid BST.
However I wanted to give you some advice. There is a lot of edge cases when you are trying to evaluate if a tree is a binary tree or not recursively. One simpler solution would be to traverse the tree in order, store the elements in an ArrayList, then check to see if the list is sorted. This implementation is much easier/simpler and also runs in the same time complexity but with a bigger space complexity: O(n) for both.
Because of this:
root.left = new Node(3);
root.left.right = new Node(2);
-> on right side there must be value higher then root - like this
root.left = new Node(2);
root.left.right = new Node(3);
I changed the method little and now it goes as following,
public static boolean isBST( Node root, int min, int max ){
if (root == null )
return true;
return ( root.data > min)
&& ( root.data < max )
&& isBST(root.left, min, root.data)
&& isBST( root.right, root.data, max );
}
While the calling is as follow,
boolean bol_ = isBST(root, min - 1 , max +1 );

Using a recursive method to find the smallest element in a subtree given the root: what am I doing wrong here?

So I have a homework question where I'm supposed to use a recursive method to "find the minimum element within a subtree rooted at the specified node"
And then I'm given this as my starting point:
public TreeNode
{
int data;
TreeNode left;
TreeNode right;
}
and
/**
Finds the minimum value for the subtree that is
rooted at a given node
#param n The root of the subtree
#return The minimum value
PRECONDITION: n is not null.
*/
int min(TreeNode n)
{
// COMPLETE THE BODY OF THIS METHOD
}
Now, I've got a very basic driver program written to insert nodes into the tree and I've written my recursive method, but it seems to be counting up instead of down, here's my method:
int min(TreeNode n){
if(n.left != null) {
n = n.left;
min(n);
System.out.println("N is now " + n.value);
}
return n.value;
}
Output of my code:
Building tree with rootvalue 25
=================================
Inserted 11 to left of node 25
Inserted 15 to right of node 11
Inserted 16 to right of node 15
Inserted 23 to right of node 16
Inserted 79 to right of node 25
Inserted 5 to left of node 11
Inserted 4 to left of node 5
Inserted 2 to left of node 4
Root is 25
N is now 2
N is now 4
N is now 5
N is now 11
The minimum integer in the given nodes subtree is: 11
Can someone please explain to me why this doesn't work?
Note: this is all assuming you're in a Binary Search Tree, so returning the minimum element means returning the left-most element.
This means your recursive call is quite simple:
min(node):
if this node has a left node:
return min(node.left)
if this node does not have a left node:
return this node's value
The logic is that if we don't have another left node then we are the left-most node, so we are the minimum value.
Now, in Java:
int min(TreeNode n){
if (n.left == null)
return n.value;
return min(n.left); // n.left cannot be null here
}
Now to explain your results, consider how this method works. It calls the method on the next node (min(n.left)) before continuing. In your case you had a println after this recursive call. Therefore the println inside the recursive call went first. So your prints started at the bottom of the tree and worked their way back up. This explains the "reverse order" printing.
Your method then returned 11 as your result because (as another answer has explained) your n = n.left didn't affect any of your recursive sub-calls, only the one in the current function call. This means you returned the left node of the root, rather than the furthest left child.
I hope this makes sense. If you need clarification on anything leave a comment or something. Recursion can be quite tricky to get your head around at first.
The issue is that Java is call-by-value, not by reference -- although references are passed by value. But what that really means in this case is that the call to min(n) does not change what the variable n refers to -- it doesn't do anything at all. What you should probably be doing is return min(n).
public static void main(String[] args) throws IOException, NoSuchMethodException, InitializationError {
Logger.getRootLogger().addAppender(new ConsoleAppender(new SimpleLayout(), "System.out"));
Logger.getRootLogger().setLevel(Level.ALL);
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
n1.data = 110;
n1.left = n2;
n1.right = n3;
n2.data = 15;
n2.left = n4;
n2.right = null;
n3.data = 3;
n3.left = null;
n3.right = null;
n4.data = 4;
n4.left = null;
n4.right = n5;
n5.data = 12;
n5.left = n6;
n5.right = null;
n6.data = 19;
n6.left = null;
n6.right = null;
System.out.print("min=" + min(n1));
}
static public class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
static int min(TreeNode n) {
return min(n, n.data);
}
static int min(TreeNode n, int min) {
System.out.println("N is now " + n.data);
int currentMin = min;
if (n.left != null && n.right != null) {
final int left = min(n.left);
final int right = min(n.right);
if (left < right) {
currentMin = left;
} else {
currentMin = right;
}
} else if (n.left != null) {
currentMin = min(n.left);
} else if (n.right != null) {
currentMin = min(n.right);
}
if (currentMin < min) {
return currentMin;
} else {
return min;
}
}
OUTPUT is:
N is now 110
N is now 15
N is now 4
N is now 12
N is now 19
N is now 3
min=3
You need to use some tree traversal algoritm, for checking every node of the tree. Also you need to store current finded minimum. Pass this minimum into recursive function. It is calling "accumulator".
The last statement in your method implementation returns the node n's value. As n starts with the root and is replaced by its left child (if exists) you always get the value of the root's left child.
The following code should do it:
int min(final Tree n){
int result;
if(n == null){
result = Integer.MAX_VALUE;
} else {
result = n.value;
final int leftResult = min(n.left);
if(leftResult < result){
result = leftResult;
}
final int rightResult = min(n.right);
if(rightResult < result){
result = rightResult;
}
}
return result;
}
Or you could use the Visitor pattern (you would need to make your tree Iterable then and pass the values to the Visitor one-by-one):
interface TreeVisitor {
void accept(int value);
}
class MinTreeVisistor implements TreeVisitor {
int min = Integer.MAX_VALUE;
#Override
public void accept(int value) {
if(value < this.min) {
this.min = value;
}
}
}

Categories

Resources