Complexity of tree traversal for printing all paths recursively - java

I have written a program to find all valid parameter combination if an input N is given. There should be N number of parameters.
For example, if N = 2, the answer will be ()(), (()) and if N = 3 the answer will be ((())), (())(), ()(()), ()()(), (()()).
I have implemented the solution using binary tree in Java. Here is my solution.
class Node {
char value;
Node right;
Node left;
public Node(char value) {
this.value = value;
}
public void insertRight(char value) {
Node node = new Node(value);
this.right = node;
}
public void insertLeft(char value) {
Node node = new Node(value);
this.left = node;
}
}
public class App
{
private static final int N = 3;
public static void main (String[] args)
{
Node tree = new Node('(');
insertNodes(tree, N - 1, 1);
printParams("", tree);
}
private static void insertNodes(Node currentNode, int remainingOpen, int remainingClose) {
if (remainingOpen > 0) {
currentNode.insertLeft('(');
insertNodes(currentNode.left, remainingOpen - 1, remainingClose + 1);
}
if (remainingClose > 0) {
currentNode.insertRight(')');
insertNodes(currentNode.right, remainingOpen, remainingClose - 1);
}
}
private static void printParams(String paramStr, Node node) {
paramStr = paramStr + node.value;
if (node.left == null && node.right == null) {
System.out.println(paramStr);
return;
}
if (node.left != null)
printParams(paramStr, node.left);
if (node.right != null)
printParams(paramStr, node.right);
}
}
I want to know the complexity of this solution. What would be the complexity for creating the tree and what would be the complexity for traversing on each path?
I know that, there will be 2 * N nodes in each path and there will be at most 2^2N children. If we are traversing each path from root, complexity may be N * 2 ^ 2N. But, I'm not able to think of complexity when recursion is involved.

The complexity for creation is given by the number of nodes you create, which is intuitive enough. Traversal is the same, since you visit each node exactly once.
In your case, the number of nodes form a Catalan sequence: https://en.wikipedia.org/wiki/Catalan_number
.

Related

Is depth between any two leaf node in binary tree greater than one

I've been working on this coding problem and have been able to successfully get the depth of each leaf node into a hash set. What I'm trying to do is determine if the difference in depth is of a leaf node is greater than one BEFORE that depth is added to the hash set. I don't want to put all of the leaf nodes in the hash set and use two for loops to check if there is a difference in depth greater than one. In my code below, the int variable count represents depth.
The problem is my code always returns true. Something is wrong with the code where is checks the difference in depths/count for each leaf node. Code is below. I'm trying to keep this method in O(n) time, and avoid O(n^2).
The depths of the four leaf nodes in this tree are : 3, 2, 2, 5
import java.util.*;
public class cakeEightWeekly {
static int count = 0;
public static class Node {
public int value;
public Node leftChild;
public Node rightChild;
public Node(int value) {
this.value = value;
}
public void setLeft(Node leftValue) {
this.leftChild = leftValue;
}
public void setRight(Node rightValue) {
this.rightChild = rightValue;
}
public Node getRight() {
return rightChild;
}
public Node getLeft() {
return leftChild;
}
}
public static boolean isBalanced(Node root) {
HashSet < Integer > hset = new HashSet < Integer > ();
if (root != null) {
count++;
isBalanced(root.getLeft());
isBalanced(root.getRight());
count--;
if (root.getLeft() == null && root.getRight() == null) {
if (!hset.isEmpty()) {
for (int x: hset) {
if ((x - count) < 0) {
int sum = count - x;
if (sum > 1) {
return false;
}
} else if ((x - count) > 1) {
return false;
}
}
hset.add(count);
} else {
hset.add(count);
}
}
}
return true;
}
public static void main(String[] args) {
Node One = new Node(1);
Node Two = new Node(2);
Node Three = new Node(3);
Node Four = new Node(4);
Node Five = new Node(5);
Node Six = new Node(6);
Node Seven = new Node(7);
Node Eight = new Node(8);
Node Nine = new Node(9);
Node Ten = new Node(10);
Node Eleven = new Node(11);
Five.setLeft(Three);
Five.setRight(Seven);
Three.setLeft(Two);
Three.setRight(Four);
Two.setLeft(One);
Seven.setLeft(Six);
Seven.setRight(Eight);
Eight.setRight(Nine);
Nine.setRight(Ten);
Ten.setRight(Eleven);
System.out.print(isBalanced(Five));
}
}

Search Double Linked List Java Recursively

I am trying to search a doubly-linked list in Java for a term, and return it if found. Here is my code so far:
private class Node {
public String content;
public Node up;
public Node left;
public Node right;
}
private Node searchList(String term, Node node) {
while (node != null) {
System.out.print(node.name + " - "); //To see process
if (node.content.equals(term)) {
return node;
} else if (node.right != null) {
return searchList(term, node.right);
}
node = node.left;
}
return null;
}
My algorithm is basically:
While the node is not null
Check if it matches the search term
If there is an element to he right, scan that with recursion
Both points are now null, item is not present
Edit with my question, sorry:
I cannot get it to search down to bottom levels and having trouble understanding where I have gone wrong.
Any help would be appreciated!
I got to agree with the comments that your question is unclear.
However, I assume you are just looking for a way to implement a recursive search on a double linked list (in which null elements are not allowed). As the other answer already mentions, I assume type Page to be a subtype of Node. In fact, I will substitute it in my example below.
Since there seems to be some misconception about implementing a double linked list and about recursion itself, I will give a condensed but running example.
The code you are presenting lacks a termination condition for the recursion. Which, unfortunately, also holds true for ikicha's solution. One way (amongst others) to accomplish this is to use a helper method to pass an invariant (eg. the start element) or counter from one iteration of the recursion to the next one.
The line node = node.left in your example has no effect. If you wanted to achieve a search in both directions (as ikicha sketched) I would be interested in why direction matters for you.
public class DoubleLinked {
private Node first;
private Node last;
private int size;
private class Node {
public String content;
public Node left;
public Node right;
public Node(String content) {
this.content = content;
}
}
private void addElement(Node addedNode) {
if (first == null) {
first = addedNode;
last = addedNode;
} else {
last.right = addedNode;
addedNode.left = last;
addedNode.right = first;
last = addedNode;
}
size++;
}
private Node searchList(String term, Node node) {
int tries = 0;
if (node != null) {
return searchHelper(term, node.right, tries);
}
return null;
}
private Node searchHelper(String term, Node node, int tries) {
if (node == null || tries >= size) {
return null;
}
if (node.content.equals(term)) {
return node;
} else {
return searchHelper(term, node.right, tries);
}
}
public static void main(String[] args) {
DoubleLinked list = new DoubleLinked();
list.addElement(list.new Node("first"));
Node startNode = list.new Node("second");
list.addElement(startNode);
list.addElement(list.new Node("third"));
list.addElement(list.new Node("forth"));
Node r = list.searchList("forth", startNode);
System.out.println(r!=null?r.content:"term not found");
}
}
I think your algorithm computes same node several times because move left and find all right nodes of the left one repeatedly.
You can find node by search two direction each from start node.
private Node internalSearchList(String term, Node node, int direction) {
if (node == null) {
return null;
}
if (term.equals(node.content)) {
return node;
} else {
return internalSearchList(term, direction == 0 ? node.left : node.right, direction);
}
}
private Node searchList(String term, Node node) {
// search to left side
Node result = internalSearchList(term, node, 0);
if (result != null) {
return result;
} else {
return internalSearchList(term, node, 1);
}
}
And also I think the type of Node.left and Node.right must be Node.
private class Node {
public String content;
public Node up;
public Node left;
public Node right;
}

How to manipulate a string (move substring to other part of string) in O(log n) using a rope or an order statistics splay tree

Two weeks ago I've finished an implementation of a splay tree that allows basic functions, like insert, delete, find key and and obtain the sum of a range of elements of the three. You can find this implementation here as reference for this question or out of curiosity.
As an extra task (its optional and its past due, I'm solving this not for a grade but because I believe its a useful data structure not easy to "Google about it"), I was asked to implement a Rope data structure to manipulate strings so if the string is "warlock" and the keys given are 0 2 2, then the string would be "lowarck" (0 2 is substring "war", "lock" is whats left after removing "war" and you insert it after 2nd char so turns into "lo"+"war"+"ck").
This is just one query but it can be up to 100k queries for a 300k character long string, so a naive solution wouldnt work.
My first doubt is about initializing the tree( For the ones who have read the gist,I'll use Node instead of Vertex in order to be easy to understand for most).
This is the Node class and the NodePair class:
class Node {
char key;
int size;
Node left;
Node right;
Node parent;
Node(char key, int size, Node left, Node right, Node parent) {
this.key = key;
this.size = size;
this.left = left;
this.right = right;
this.parent = parent;
}
}
class NodePair {
Node left;
Node right;
NodePair() {
}
NodePair(Node left, Node right) {
this.left = left;
this.right = right;
}
}
After that, I create the tree this way:
StringBuffer sb = new StringBuffer(br.readLine());
Node left=null;
for (int i=0;i<sb.length();i++){
root=new Vertex(sb.charAt(i), i+1, left, null, null);
if (i!=sb.length()-1){
left=root;
}
}
This creates a very unbalanced tree where the first char of the string (as node.key) has node.size 1 and is the leftmost child; and the last char of the string is the root with size=sb.length().
I am not completely sure if this is correctly initialized. I did an inorder traversal print with key and size and I got the whole string in size order, which is what I expected.
After that I have modified the Update method from this:
void update(Node v) {
if (v == null) return;
v.sum = v.key + (v.left != null ? v.left.sum : 0) + (v.right != null ? v.right.sum : 0);
if (v.left != null) {
v.left.parent = v;
}
if (v.right != null) {
v.right.parent = v;
}
}
To this: (based on CLRS chapter 14.1)
void update(Node v) {
if (v == null) return;
v.size = 1 + (v.left != null ? v.left.size : 0) + (v.right != null ? v.right.size : 0);
if (v.left != null) {
v.left.parent = v;
}
if (v.right != null) {
v.right.parent = v;
}
}
Then the find method, from the original:
NodePair find(Node root, int key) {
Node v = root;
Node last = root;
Node next = null;
while (v != null) {
if (v.key >= key && (next == null || v.key < next.key)) {
next = v;
}
last = v;
if (v.key == key) {
break;
}
if (v.key < key) {
v = v.right;
} else {
v = v.left;
}
}
root = splay(last);
return new NodePair(next, root);
}
to this:(Based in the Order Statistics-SELECT of CLRS Chapter 14.1)
Node find(Node r, int k){
int s = r.left.size + 1;
if (k==s) return r;
else if (k < s) {
return find(r.left,k);
}
return find(r.right,k-s);
}
However I already have a problem at this point since, as you can see, the original find returns a NodePair while this method returns a Node.
The explanation of the NodePair according to instructors is:
Returns pair of the result and the new root.If found, result is a
pointer to the node with the given key.Otherwise, result is a pointer
to the node with the smallest bigger key (next value in the order). If
the key is bigger than all keys in the tree, then result is null.
This complicates my split method since it uses Find method to look for the node to split.
Besides this, I'm obtaining NullPointerException at this find method and from other students I understand that to avoid other error we should use a non-recursive version, so basically I need to implement a non-recursive version of OS-Select that returns a NodePair as the previous find method or modify my split method which is:
NodePair split(Node root, int key) {
NodePair result = new NodePair();
NodePair findAndRoot = find(root, key);
root = findAndRoot.right;
result.right = findAndRoot.left;
if (result.right == null) {
result.left = root;
return result;
}
result.right = splay(result.right);
result.left = result.right.left;
result.right.left = null;
if (result.left != null) {
result.left.parent = null;
}
update(result.left);
update(result.right);
return result;
}
As you can see, the find method is assigned to the NodePair findAndRoot.
I believe that besides the OS-Select conversion to non-recursive my main problem is to understand the way NodePair is used by the previous find method and split method.
Finally, this is my implementation of the method to receive the tree and keys and manipulate them:
Node stringManip(Node v, int i, int j, int k){
Node left;
Node right;
NodePair middleRight =split(v,j+1);
left=middleRight.left;
right=middleRight.right;
NodePair leftMiddle = split(left,i);
Node start = leftMiddle.left;
Node substr = leftMiddle.right;
Node tmp = merge(start, right);
NodePair pairString = split(tmp,k+1);
Vertex fLeft =pairString.left;
Vertex fRight = pairString.right;
root = merge(merge(fLeft,substr),fRight);
root = splay(root);
update(root);
return root;
}
As you must realize from my code, I'm a beginner with only have 5 months that started learning to program and I picked Java, so from the info I've gathered I get that this type of data structure is more in the intermediate-expert level (I'm already surprise I was capable of implementing the previous splay tree.
So please, consider my beginner level in your answer.
PD: Here's a pseudocode version of the nonrecursive OS-Select, still having NullPointerException..
OS-SELECT(x, i)
while x != null
r <- size[left[x]]+1
if i = r
then return x
elseif i < r
x = left[x]
else
x = right[x]
i = i - r

Methods binary tree

I had to do some methods about BinaryTree (no Search Binary Tree). I'm not able to do 3 methods: reflect (reflect the tree, my code don't work beacuse reflect only a part of the tree), cut and cut2. The code is:
public class BinaryTree {
protected class Node {
Integer element;
Node left;
Node right;
Node(int element) {
this.element = element;
left = right = null;
}
Node(int element, Node left, Node right) {
this.element = element;
this.left = left;
this.right = right;
}
// is leaf?
boolean isLeaf() {
return left == null && right == null;
}
}
protected Node root;
public BinaryTree() {
root = null;
}
/* doesn't work */
public void reflect() {
if (root == null)
return;
reflect(root);
}
protected void reflect(Node node) {
reflect(node.left);
reflect(node.right);
Node temp = new Node(node.left.element);
node.left.element = node.right.element;
node.right.element = temp.element;
}
/* this method had to trim the tree at level h,
if h=0, it cut the whole tree. It change the original tree */
/* doesn't work */
public void cut(int h) {
}
/* i can change parameters */
protected void cut(Node node, int h) {
}
/* this method had to trim the tree at level h,
if h=0, it cut the whole tree. It doesn't change the original tree,
it returns a new tree */
/* doesn't work */
public BinaryTree cut2(int h) {
}
/* i can change parameters */
protected BinaryTree cut2(Node node, int h) {
}
}
}
I'm not able to do the methods reflect cut and cut2. Help me please, thank you!
This smells like homework, and even though the tag was pruned, I don't think us writing complete implementations of binary trees is the right thing.
Having said that, can you explain what isn't clear about implementing both of those methods? They're pretty much equal, except for the tree copying needed for cut2. I'd implement it via a recursive private method cutInternal(Node n, int currLevel, int h) passing in the level number that we're currently at. Then, when currLevel == h we just prune both nodes and return.
You almost had reflect right. Just avoid creating new Node objects:
protected void reflect(Node node) {
if (node != null) {
reflect(node.left);
reflect(node.right);
Node temp = node.left;
node.left = node.right;
node.right = temp;
}
}
As for cut:
public void cut(int h) {
if (h == 0) {
root = null;
} else {
cut(root, h - 1);
}
}
Then you can write cut(Node, int):
protected void cut(Node node, int h) {
if (node != null) {
if (h == 0) {
node.left = node.right = null;
} else {
cut(node.left, h - 1);
cut(node.right, h - 1);
}
}
}
See if you can work out cut2 on your own using the above as a start.

Lowest Common Ancestor of a Binary Tree

This is a popular interview question and the only article I can find on the topic is one from TopCoder. Unfortunately for me, it looks overly complicated from an interview answer's perspective.
Isn't there a simpler way of doing this other than plotting the path to both nodes and deducing the ancestor? (This is a popular answer, but there's a variation of the interview question asking for a constant space answer).
A simplistic (but much less involved version) could simply be (.NET guy here Java a bit rusty, so please excuse the syntax, but I think you won't have to adjust too much). This is what I threw together.
class Program
{
static void Main(string[] args)
{
Node node1 = new Node { Number = 1 };
Node node2 = new Node { Number = 2, Parent = node1 };
Node node3 = new Node { Number = 3, Parent = node1 };
Node node4 = new Node { Number = 4, Parent = node1 };
Node node5 = new Node { Number = 5, Parent = node3 };
Node node6 = new Node { Number = 6, Parent = node3 };
Node node7 = new Node { Number = 7, Parent = node3 };
Node node8 = new Node { Number = 8, Parent = node6 };
Node node9 = new Node { Number = 9, Parent = node6 };
Node node10 = new Node { Number = 10, Parent = node7 };
Node node11 = new Node { Number = 11, Parent = node7 };
Node node12 = new Node { Number = 12, Parent = node10 };
Node node13 = new Node { Number = 13, Parent = node10 };
Node commonAncestor = FindLowestCommonAncestor(node9, node12);
Console.WriteLine(commonAncestor.Number);
Console.ReadLine();
}
public class Node
{
public int Number { get; set; }
public Node Parent { get; set; }
public int CalculateNodeHeight()
{
return CalculateNodeHeight(this);
}
private int CalculateNodeHeight(Node node)
{
if (node.Parent == null)
{
return 1;
}
return CalculateNodeHeight(node.Parent) + 1;
}
}
public static Node FindLowestCommonAncestor(Node node1, Node node2)
{
int nodeLevel1 = node1.CalculateNodeHeight();
int nodeLevel2 = node2.CalculateNodeHeight();
while (nodeLevel1 > 0 && nodeLevel2 > 0)
{
if (nodeLevel1 > nodeLevel2)
{
node1 = node1.Parent;
nodeLevel1--;
}
else if (nodeLevel2 > nodeLevel1)
{
node2 = node2.Parent;
nodeLevel2--;
}
else
{
if (node1 == node2)
{
return node1;
}
node1 = node1.Parent;
node2 = node2.Parent;
nodeLevel1--;
nodeLevel2--;
}
}
return null;
}
}
Constant space answer: (although not necessarily efficient).
Have a function findItemInPath(int index, int searchId, Node root)
then iterate from 0 .. depth of tree, finding the 0-th item, 1-th item etc. in both search paths.
When you find i such that the function returns the same result for both, but not for i+1,
then the i-th item in the path is the lowest common ancestor.
The main reason why the article's solutions are more complicated is that it is dealing with a two-stage problem- preprocessing and then queries- while from your question it sounds like you're only doing one query so preprocessing doesn't make sense. It's also dealing with arbitrary trees rather than binary trees.
The best answer will certainly depend on details about the tree. For many kinds of trees, the time complexity is going to be O(h) where h is the tree's height. If you've got pointers to parent nodes, then the easy "constant-space" answer is, as in Mirko's solution, to find both nodes' height and compare ancestors of the same height. Note that this works for any tree with parent links, binary or no. We can improve on Mirko's solution by making the height function iterative and by separating the "get to the same depth" loops from the main loop:
int height(Node n){
int h=-1;
while(n!=null){h++;n=n.parent;}
return h;
}
Node LCA(Node n1, Node n2){
int discrepancy=height(n1)-height(n2);
while(discrepancy>0) {n1=n1.parent;discrepancy--;}
while(discrepancy<0) {n2=n2.parent;discrepancy++;}
while(n1!=n2){n1=n1.parent();n2=n2.parent();}
return n1;
}
The quotation marks around "constant-space" are because in general we need O(log(h)) space to store the heights and the difference between them (say, 3 BigIntegers). But if you're dealing with trees with heights too large to stuff in a long, you likely have other problems to worry about that are more pressing than storing a couple nodes' heights.
If you have a BST, then you can easily take a common ancestor (usu. starting with root) and check its children to see whether either of them is a common ancestor:
Node LCA(Node n1, Node n2, Node CA){
while(true){
if(n1.val<CA.val & n2.val<CA.val) CA=CA.left;
else if (n1.val>CA.val & n2.val>CA.val) CA=CA.right;
else return CA;
}
}
As Philip JF mentioned, this same idea can be used in any tree for a constant-space algorithm, but for a general tree doing it this way will be really slow since figuring out repeatedly whether CA.left or CA.right is a common ancestor will repeat a lot of work, so you'd normally prefer to use more space to save some time. The main way to make that tradeoff would be basically the algorithm you've mentioned (storing the path from root).
It matters what kind of tree you are using. You can always tell if a node is the ancestor of another node in constant space, and the top node is always a common ancestor, so getting the Lowest Common Ancestor in constant space just requires iterating your way down. On a binary search tree this is pretty easy to do fast, but it will work on any tree.
Many different trade offs are relevant for this problem, and the type of tree matters. The problem tends is much easier if you have pointers to parent nodes, and not just to children (Mirko's code uses this)
See also:
http://en.wikipedia.org/wiki/Lowest_common_ancestor
The obvious solution, that uses log(n) space, (n is the number of nodes) is the algorithm you mentioned. Here's an implementation. In the worst case it takes O(n) time (imagine that one of the node you are searching common ancestor for includes the last node).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Node
{
private static int counter = 0;
private Node left = null;
private Node right = null;
public int id = counter++;
static Node constructTreeAux(int depth)
{
if (depth == 0)
return null;
Node newNode = new Node();
newNode.left = constructTree(depth - 1);
newNode.right = constructTree(depth - 1);
return newNode;
}
public static Node constructTree(int depth)
{
if (depth == 0)
return null;
Node root = new Node();
root.left = constructTreeAux(depth - 1);
root.right = constructTreeAux(depth - 1);
return root;
}
private List<Node> findPathAux(List<Node> pathSoFar, int searchId)
{
if (this.id == searchId)
{
if (pathSoFar == null)
pathSoFar = new List<Node>();
pathSoFar.Add(this);
return pathSoFar;
}
if (left != null)
{
List<Node> result = left.findPathAux(null, searchId);
if (result != null)
{
result.Add(this);
return result;
}
}
if (right != null)
{
List<Node> result = right.findPathAux(null, searchId);
if (result != null)
{
result.Add(this);
return result;
}
}
return null;
}
public static void printPath(List<Node> path)
{
if (path == null)
{
Console.Out.WriteLine(" empty path ");
return;
}
Console.Out.Write("[");
for (int i = 0; i < path.Count; i++)
Console.Out.Write(path[i] + " ");
Console.Out.WriteLine("]");
}
public override string ToString()
{
return id.ToString();
}
/// <summary>
/// Returns null if no common ancestor, the lowest common ancestor otherwise.
/// </summary>
public Node findCommonAncestor(int id1, int id2)
{
List<Node> path1 = findPathAux(null, id1);
if (path1 == null)
return null;
path1 = path1.Reverse<Node>().ToList<Node>();
List<Node> path2 = findPathAux(null, id2);
if (path2 == null)
return null;
path2 = path2.Reverse<Node>().ToList<Node>();
Node commonAncestor = this;
int n = path1.Count < path2.Count? path1.Count : path2.Count;
printPath(path1);
printPath(path2);
for (int i = 0; i < n; i++)
{
if (path1[i].id == path2[i].id)
commonAncestor = path1[i];
else
return commonAncestor;
}
return commonAncestor;
}
private void printTreeAux(int depth)
{
for (int i = 0; i < depth; i++)
Console.Write(" ");
Console.WriteLine(id);
if (left != null)
left.printTreeAux(depth + 1);
if (right != null)
right.printTreeAux(depth + 1);
}
public void printTree()
{
printTreeAux(0);
}
public static void testAux(out Node root, out Node commonAncestor, out int id1, out int id2)
{
Random gen = new Random();
int startid = counter;
root = constructTree(5);
int endid = counter;
int offset = gen.Next(endid - startid);
id1 = startid + offset;
offset = gen.Next(endid - startid);
id2 = startid + offset;
commonAncestor = root.findCommonAncestor(id1, id2);
}
public static void test1()
{
Node root = null, commonAncestor = null;
int id1 = 0, id2 = 0;
testAux(out root, out commonAncestor, out id1, out id2);
root.printTree();
commonAncestor = root.findCommonAncestor(id1, id2);
if (commonAncestor == null)
Console.WriteLine("Couldn't find common ancestor for " + id1 + " and " + id2);
else
Console.WriteLine("Common ancestor for " + id1 + " and " + id2 + " is " + commonAncestor.id);
}
}
}
The bottom up approach described here is an O(n) time, O(1) space approach:
http://www.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
Node *LCA(Node *root, Node *p, Node *q) {
if (!root) return NULL;
if (root == p || root == q) return root;
Node *L = LCA(root->left, p, q);
Node *R = LCA(root->right, p, q);
if (L && R) return root; // if p and q are on both sides
return L ? L : R; // either one of p,q is on one side OR p,q is not in L&R subtrees
}

Categories

Resources