Find node N in a tree - java

I am having trouble coding in Java the following method
int findNodeN(Node node, int n)
For example if the binary search tree is constructed as following:
20
10 30
1 14 25 35
Then node 1 would be returned if n=0, node 10 would be returned if n = 1 and so on (i.e inOrder traversal)
Appreciate any help

The simplest realization is to set counter variable to zero. Walk the tree in the usual order. When you go to right child - increase the counter, when you go to the parent and you were in the left child - increase the counter. When the counter becomes equal to N return current vertex.

Here's a version I have, it's a bit different from what you need, but it's something to work from:
public E findElement(E element)
{
TreeNode<E> current = root;
while (current != null)
{
if ( element.compareTo(current.getElement() ) == 0) //If found
{
return current.getElement();
}
else if( element.compareTo(current.getElement() ) < 0) //If element is less
{
current = current.getLeftChild(); //Try the left child
}
else //If element is greater
{
current = current.getRightChild(); //Try the right child
}
}
//not found
return null;
}
Pretty sure you can use recursion to get some more concise code, but this gets the job done.
EDIT: OK, try something like this:
public int findNodeN(Node node, int n, int callNumber) //Call initially with findNodeN(tree.getRoot(), n, 0)
{
if (node.hasLeft())
findNodeN(node.getLeftChild(), n, callNumber);
if (callNumber == n)
return node.getElement();
else
callNumber++;
if (node.hasRight())
printTreeInOrder(node.getRightChild(), n, callNumber);
}
This isn't tested.
Calum

Related

Solution timing out for question: build binary tree from inorder and postorder

I've been grinding leetcode recently and am perplexed on why my solution is timing out when I submit it to Leetcode.
Here is the question:
https://leetcode.com/explore/learn/card/data-structure-tree/133/conclusion/942/
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
Here is my solution that times out in one of the test cases:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder == null || inorder.length == 0) {
return null; // input error
}
if (postorder == null || postorder.length == 0) {
return null; // input error
}
if (postorder.length != inorder.length) {
return null; // input error
}
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
return buildBinaryTree(inOrder, postOrder);
}
public TreeNode buildBinaryTree(List<Integer> inOrder, List<Integer> postOrder) {
boolean found = false;
int root = 0;
int rootIndex = 0;
// for given in-order scan the post-order right to left to find the root
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
root = inOrder.get(rootIndex);
found = true;
break;
}
}
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
if (rootIndex > 0) {
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
}
if ((rootIndex + 1) < inOrder.size()) {
rightOfRoot.addAll(inOrder.subList(rootIndex + 1, inOrder.size()));
}
TreeNode node = new TreeNode(root);
node.left = buildBinaryTree(leftOfRoot, postOrder);
node.right = buildBinaryTree(rightOfRoot, postOrder);
return node;
}
return null;
}
}
Can anyone help determine why this is happening? I'm thinking it is the Leetcode judge at fault here and my code is fine.
Leetcode's judge is probably OK. This code is too casual about nested linear array operations and heap allocations. Creating ArrayLists and calling contains, addAll, subList and indexOf may appear innocuous, but they should all be thought of as extremely expensive operations when inside a recursive function that spawns two child calls in every frame.
Let's unpack the code a bit:
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
This is a minor up-front cost but it's an omen of things to come. We've done 2 heap allocations that weren't necessary and walked n. I'd stick to primitive arrays here--no need to allocate objects other than the result nodes. A lookup map for inOrder with value -> index pairs might be useful to allocate if you feel compelled to create a supporting data structure here.
Next, we step into buildBinaryTree. Its structure is basically:
function buildBinaryTree(root) {
// do some stuff
if (not base case reached) {
buildBinaryTree(root.left)
buildBinaryTree(root.right)
}
}
This is linear on the number of nodes in the tree, so it's important that // do some stuff is efficient, hopefully constant time. Walking n in this function would give us quadratic complexity.
Next there's
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
This looks bad, but by definition the root is always the last element in a postorder traversal array, so if we keep a pointer to it, we can remove this outer loop. You can use indexOf directly and avoid the contains call since indexOf returns -1 to indicate a failed search.
The code:
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
does more unnecessary heap allocations for every call frame.
Here,
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
Walks the list twice, once to create the sublist and again to add the entire sublist to the ArrayList. Repeat for the right subtree for two full walks on n per frame. Using start and end indices per call frame means you never need to allocate heap memory or copy anything to prepare the next call. Adjust the indices and pass a reference to the same two arrays along the entire time.
I recommend running your code with a profiler to see exactly how much time is spent copying and scanning your ArrayLists. The correct implementation should do at most one walk through one of the lists per call frame to locate root in inOrder. No array copying should be done at all.
With these modifications, you should be able to pass, although wrangling the pointers for this problem is not obvious. A hint that may help is this: recursively process the right subtree before the left.
Yes, it would be much faster with arrays. Try this:
public static TreeNode buildTree(int[] inorder, int[] postorder, int start,
int end) {
for (int i = postorder.length-1; i >= 0; --i) {
int root = postorder[i];
int index = indexOf(inorder, start, end, root);
if (index >= 0) {
TreeNode left = index == start
? null
: buildTree(inorder, postorder, start, index);
TreeNode right = index+1 == end
? null
: buildTree(inorder, postorder, index+1, end);
return new TreeNode(root, left, right);
}
}
return null;
}
private static int indexOf(int[] array, int start, int end, int value) {
for (int i = start; i < end; ++i) {
if (array[i] == value) {
return i;
}
}
return -1;
}

Deleting a Node from a Linked List

I'm trying to delete a given Node from a Linked List. I don't know why my code is not working. Any hints?
So I have [11,21,31,41] and they are asking me to delete the node at index 2 in this case 31. So far I have this:
public void delete (int k) {
//[ 11 21 31 41 ].delete( 2 ): expected=[ 11 21 41 ]
if (k < 0 || k >= N) throw new IllegalArgumentException ();
for(Node x = first; x != null; x = x.next) {
//deletes node
if(x.item == k){
x = x.next;
}
if(x.item <= k){
x = x.next.next;
}
}
}
Can someone tell me please why is this not working? Thank you
You could move nodes using next k times. Store a temporary int and a previous node. Decrement the temporary int each time you call next(). Once you are at 0 (the desired element), remove by setting the previous node's next pointer to x's next pointer, and then set x to null.
I think in your code you are missing the part where pointers are set.
For example:
(1) -> (2) -> (3)
To remove (2), set (1).next = (3) and (2) = null. This will get:
(1) -> (3)
There are a couple of things going wrong here, and I encourage you to work on some println debugging to better understand the issues as you develop.
Assuming the item field is the value of the Node, you're comparing that value of a Node to the index of said Node (e.g. x.item == k).
The general logic that you're going to want to follow is, "if the Node the iterator is pointing to is the next Node in my list, set my next to its next."
In your code you are comparing the value of node with the index you passed. This comparison will always have index less than value in node. Also after that you are not updating the node when you assume the code is correct.
Below code should give you the result.
public void delete (int k)
{
//[ 11 21 31 41 ].delete( 2 ): expected=[ 11 21 41 ]
if (k < 0 || k >= N) throw new IllegalArgumentException ();
int count = 0;//Assuming index starts from 0
Node prev;
for(Node x = first; x != null; x = x.next)
{
//deletes node
count++;
if(count<k)
{
prev = x;
continue;
}
else
{
prev.next = x.next;
x.next = null;
break;
}
}
if(count>k || count<k)
{
System.out.println("No element with index k");
}
}
#vase is correct saying
Assuming the item field is the value of the Node, you're comparing
that value of a Node to the index of said Node (e.g. x.item == k).
some example code that could fix this
public void delete(int k){
Node n = first;
for(int i = 0; i < k-1; i++){ // this loop finds the node right before the
n=n.next; // index to use to delete the desired index.
}
n.next = n.next.next; // delete command
}

Walk tree data structure to find its height and count elements in one loop

I have a tree structure.
class Element {
private List<Element> children;
}
Element treeStructure = produceSomeTreeStructure();
//How to get its height and number of elements.
Straight-forward solution is to make two loops. In first I can find number of nodes
A question on getting number of nodes in a Binary Tree
(change this algorithm for non-binary tree),
and the second loop to get the tree's height
http://www.geeksforgeeks.org/iterative-method-to-find-height-of-binary-tree/
Again, adapt this algorithm to non-binary tree.
My question, how to do this in one walk. It is acceptable for me to keep results in global variables.
If you want to know the number of nodes, then you'll need to explore the whole tree. The easiest way to do this is with a depth-first search, where you count the nodes as you go.
A depth-first search algorithm can also easily enough count the depth to which it's currently exploring, and the maximum depth reached overall. Modify the depth-first search algorithm to take both of these as arguments.
If you code it recursively (easiest), then you can simply add one to the depth argument every time you make a recursive call. And if this gives you a number that's greater than the maximum that you're keeping track of, then update the maximum to the current depth.
Yes that can be done as it is shown in the below code. Just add the counter totalNodeCount and do +1 each time you traverse a node in BFS style.
// Iterative method to find height and node-count of Binary Tree
int treeHeightAndNumOfNodes(node *root)
{
// Base Case
if (root == NULL)
return 0;
// Create an empty queue for level order tarversal
queue<node *> q;
// Enqueue Root and initialize height
q.push(root);
int height = 0;
int totalNodeCount = 0; // <-- Use this counter to store total number of node traversed.
while (1)
{
// nodeCount (queue size) indicates number of nodes
// at current lelvel.
int nodeCount = q.size();
if (nodeCount == 0)
return height;
height++;
// Dequeue all nodes of current level and Enqueue all
// nodes of next level
while (nodeCount > 0)
{
node *node = q.front();
q.pop();
if (node->left != NULL)
q.push(node->left);
if (node->right != NULL)
q.push(node->right);
nodeCount--;
totalNodeCount++; // <-- Update this counter
}
}
}
Again, adapt this algorithm to non-binary tree.
To do that, replace the given below lines of codes with a loop that traverse through each child nodes and push the NON-NULL children into queue.
if (node->left != NULL)
q.push(node->left);
if (node->right != NULL)
q.push(node->right);
What you are looking for is a bit like a BFS. You just have to walk your tree like the following:
int getHeight(Element e) {
int max_height = 0;
for (Element child : e.children) {
max_height = max(max_height, getHeight(child));
}
return max_height + 1;
}
Similarly, getting the total number of elements is easy: instead of getting the maximum value among the node's children, you just add them up.
int getTotalCount(Element e) {
int total_count = 0;
for (Element child : e.children) {
total_count += getTotalCount(el);
}
return total_count + 1;
}
If you must return the two numbers using the same function, just pack them in a common class to traverse your tree only once.
Thanks guys for your answers.
And this is what I have coded.
public static TreeData countElementsAndFindHeight(Element root) {
TreeData treePair = new TreeData();
if (root == null) {
return treePair;
}
treePair.nElements = 1;
treePair.height = 1;
//Nodes queue will contain all the elements of the trees, so its size is the number of elements.
List<Element> nodesQueue = new LinkedList<Element>();
treePair.walkedNodes = nodesQueue;
List<Element> children = root.getChildren();
if (CommonUtils.isCollectionEmpty(children)) {
return treePair;
}
treePair.height = countElementsAndFindHeight(root, nodesQueue);
nodesQueue.add(root);
treePair.nElements = nodesQueue.size();
return treePair;
}
private static int countElementsAndFindHeight(Element root, List<Element> nodesQueue) {
int maxHeight = 1;
List<Element> children = root.getChildren();
if (CommonUtils.isCollectionEmpty(children)) {
return maxHeight;
}
for (Element childElement : children) {
int childHeight = countElementsAndFindHeight(childElement, nodesQueue);
if (childHeight > maxHeight) {
maxHeight = childHeight;
}
nodesQueue.add(childElement);
}
return maxHeight + 1;
}
public static class TreeData {
protected int height = 0;
protected int nElements = 0;
}

How to determine the space and time complexity of these two algorithms?

I was practicing one algorithm exercise today from HackerRank: https://www.hackerrank.com/challenges/find-the-merge-point-of-two-joined-linked-lists
I decided to solve this problem with two solutions.
First algorithm, based on Floyd's algorithm:
/*
Insert Node at the end of a linked list
head pointer input could be NULL as well for empty list
Node is defined as
class Node {
int data;
Node next;
}
*/
int FindMergeNode(Node headA, Node headB) {
// Complete this function
// Do not write the main method.
int length1 = countLength(headA);
int length2 = countLength(headB);
int d = Math.abs(length1 - length2);
return (length1 > length2) ?
findIntersection(d, headA, headB) : findIntersection(d, headB, headA);
}
int countLength(Node head) {
Node current = head;
int counter = 0;
while (current != null) {
current = current.next;
counter++;
}
return counter;
}
int findIntersection(int d, Node headA, Node headB) {
Node currentA = headA;
Node currentB = headB;
for (int i = 0; i < d; i++) {
currentA = currentA.next;
}
while (currentA != null && currentB != null) {
if (currentA == currentB) return currentA.data;
currentA = currentA.next;
currentB = currentB.next;
}
return -1;
}
Second algorithm, using one outer and inner loop:
/*
Insert Node at the end of a linked list
head pointer input could be NULL as well for empty list
Node is defined as
class Node {
int data;
Node next;
}
*/
int FindMergeNode(Node headA, Node headB) {
Node currentA = headA;
while (currentA != null) {
Node currentB = headB;
while (currentB != null) {
if (currentA == currentB) {
return currentA.data;
}
currentB = currentB.next;
}
currentA = currentA.next;
}
return -1;
}
Honestly, I'm sure that the first algorithm is better than the second because of its performance. I would like to demonstrate this performance using SPACE and TIME COMPLEXITY, I have not dominated those topics.
According to the material, this solution should be Time Complexity: O(N). But I'm not quite sure that the first algorithm will be O(N).
The first algorithm scans headA and headB once to find the lengths, then skips the extra elements of the longer chain, then scans in parallel the two chains. The time complexity is proportional to the length of the chains, so it is O(N). It doesn't matter if you scan the lists 2, 3, or 5 times, as long as that number is constant, the time complexity is still O(N).
The second algorithm is worse, for each element in headA before the merge point, it scans the entire headB. In the worst case, when the lists don't intersect at the last node, it will scan all elements of headB for each element of headA. So the time complexity of this is O(N^2).
The space complexity of both algorithms is O(1), because you use constant storage in both (a bunch of local variables), that don't change, regardless the size of the input lists.
The first one is O(N) where N is in abstract the greatest of the two list length. Since you have two for loops and each can cost at max N, in the worst case the first algorithm will take 2 N cycle to end. So since O hide constant factor the algorithm is O(N)

Implementing a Min Heap with an Array: Insert and Remove Min (with duplicates)

I'm trying to implement a Min Heap in Java, but I'm having issues with inserting and removing elements (inserting at the end, removing the root as min). It seems to work for the most part (I use a program to visually display the heap and have been printing out the new roots when min has been removed, things like that).
My problem is, for some reason the root won't switch with a new item when a new item is added, but I can't figure out why at all. Also, it seems this is only the problem when there are a lot of duplicates, the heap doesn't seem completely capable of staying in order (the parent is smaller than the children). For the most part, it does. Only occasionally it doesn't, and to me it seems random.
This is done with generics, and basically following most algorithms. Everything else I know for a fact works, it's definitely a problem with these two methods.
public void insert(T e) {
if (size == capacity)
increaseSize(); //this works fine
last = curr; //keeping track of the last index, for heapifying down/bubbling down when removing min
int parent = curr/2;
size++; //we added an element, so the size of our data set is larger
heap[curr] = e; //put value at end of array
//bubble up
int temp = curr;
while (temp > 1 && ((Comparable<T>) heap[temp]).compareTo(heap[parent]) < 0) { //if current element is less than the parent
//integer division
parent = temp/2;
swap(temp, parent); //the swapping method should be correct, but I included it for clarification
temp = parent; //just moves the index value to follow the element we added as it is bubbled up
}
curr++; //next element to be added will be after this one
}
public void swap(int a, int b){
T temp = heap[a];
heap[a] = heap[b];
heap[b] = temp;
}
public T removeMin() {
//root is always min
T min = heap[1];
//keep sure array not empty, or else size will go negative
if (size > 0)
size--;
//put last element as root
heap[1] = heap[last];
heap[last] = null;
//keep sure array not empty, or else last will not be an index
if (last > 0)
last--;
//set for starting at root
int right = 3;
int left = 2;
int curr = 1;
int smaller = 0;
//fix heap, heapify down
while(left < size && right < size){ //we are in array bounds
if (heap[left] != null && heap[right] != null){ //so no null pointer exceptions
if (((Comparable<T>)heap[left]).compareTo(heap[right]) < 0) //left is smaller
smaller = left;
else if (((Comparable<T>)heap[left]).compareTo(heap[right]) > 0) //right is smaller
smaller = right;
else //they are equal
smaller = left;
}
if (heap[left] == null || heap[right] == null)//one child is null
{
if (heap[left] == null && heap[right] == null)//both null, stop
break;
if (heap[left] == null)//right is not null
smaller = right;
else //left is not null
smaller = left;
}
if (((Comparable<T>)heap[curr]).compareTo(heap[smaller]) > 0)//compare smaller or only child
{
swap(curr,smaller); //swap with child
curr = smaller; //so loop can check new children for new placement
}
else //if in order, stop
break;
right = 2*curr + 1; //set new children
left = 2*curr;
}
return min; //return root
}
Any variables not declared in the methods are global, and I know a couple of things are probably redundant, like the whole current/last/temp situation in add, so I'm sorry about that. I tried to make all names self explanatory and explain all the checks I did in removeMin. Any help would be insanely appreciated, I've gotten as far as I can looking things up and debugging. I think I'm just fundamentally missing something here.
Just to help you debug, you should simplify the code. There is something strange going on with 'last' variable. Also in 'insert' when you do the loop, probably temp should go to 0, that is
while (temp >= 0 &&......

Categories