Recursion in java and maintaining states of variables across stacks - java

I was trying to solve a problem in BST where the question was "Check if all leaves are at same level"
In this question, I need to keep incrementing the level per stack call but also maintain a value across all calls, the maximum level. Along with this, I need to return a boolean with the result.
It is simple enough to solve, I need to keep doing down the tree, I did this
int maxlevel = 0;
public boolean allAtSameLevel(Node root, int level){
if(root== null){
return false;
}
if(root.left== null && root.right == null){
if(maxlevel == 0){
maxlevel = level;
}
return(level== maxlevel);
}
return allAtSameLevel(root.left, level+1) && allAtSameLevel(root.right, level+1) ;
}
My problem is that for a value that needs to be shared, I have to maintain an instance variable in java. Is there a better way to do this? My confusion is that since, it's going to go all the way to the right leaf first and then go up, passing the value won't help. Any ideas?

The trick is to communicate the depth of the subtree back to the higher level of the stack, but doing so only when both right and left depths are the same. You can do it with a simple recursive function:
int eqDepth(Node n) {
if (n == null) return 0; // This is a leaf, its subtree depth is zero
int dLeft = eqDepth(n.left); // Make two recursive calls
int dRight = eqDepth(n.right);
// If one of the depths is negative, or the depths are different,
// report it by returning negative 1:
if (dLeft < 0 || dRight < 0 || dLeft != dRight) return -1;
return 1+dLeft; // It's the same as dRight
}
With this function in hand, you can code allAtSameLevel in one line:
public boolean allAtSameLevel(Node root) {
return eqDepth(root) >= 0;
}
Here is a demo on ideone. It starts off with an unbalanced tree and gets a -1
a
/ \
b c
/ \ / \
d e f -
then adds the missing node
a
/ \
b c
/ \ / \
d e f g
and gets a positive result.

Related

Why won't my solution work to find minimum depth of a binary tree?

I don't understand how my solution for finding minimum depth of a binary tree doesn't work? What am I doing wrong?
Here's a link to the problem if you're curious: https://leetcode.com/problems/minimum-depth-of-binary-tree/submissions/
public int minDepth(TreeNode root) {
if(root == null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
int ans = Math.min(left, right) + 1;
return ans;
}
Your code will not work in the case only one side is null, like
3
/ \
20
/ \
15 7
as it will return 1 (while 3 is not a leaf).
You need to test if one side is null, ignore it and deal with the other side

Prime Number checker is not working

This is the code for a function that is supposed to return true if the input is prime and returns false if it is not.
This is how I intended for it to work: lets say that y = 7, the loop starts with n=1. Since 1(n) is less that 7(y) the loop can iterate. The program checks if y divided by n has a remainder of 0, meaning that n is a factor of y. If it is true, then it checks to see if the factor does not equal 1 or y (7), because if they dont then that means that y has more factors other than its self and 1, meaning that it is not prime, so it should automatically end the function and return false. but since 7 has only two factors, 1 and 7, and they either equal 1 or itself (y) then after the end of the loop, it should return true.
I don't understand why it isn't working.
public static boolean checkIfPrime(long y) {
for ( long n =1L; n <= y; n++) {
if(y%n == 0) {
if( n != 1L || n != y) {
return false;
}
}
}
return true;
}
With a few optimizations the code will be like this
static boolean isPrime(long n){
long lim = (long) Math.sqrt(n);
if(n%2 == 0 && n != 2)
return false;
for (int i = 3; i <= lim; i=i+2)
if(n%i == 0)
return false;
return true;
}
This code:
checks if the number is even and different from 2 (all even numbers
except 2 are compound).
next iterates from 3 to sqrt(n), thats because to prove a number is
prime you don't need to check all the dividers (if you don't believe
me try, and if still don't believe use n/2 wich is enough but not the
minimum value).
For loop pace start from 3 and add 2 in each iteration getting only odd numbers as divder (we first checked that it wasn't an even number).
Remove equal to operator in n <= y. Start your loop from 2. It must be like this. ( long n =2; n < y; n++)
For what you are trying to achieve, pseudo code in my opinion should look like this:
set a flag = true;
Loop from 2 to y-1{
if(y%n==0){
flag = false
break; // Very important
}
}
check flag condition & return (if some othe computation is required) or just return flag
if( n != 1L || n != y) : is adding a check condition unnecessarily to every iteration. try to avoid it.
Why use a flag instead of direct return statement ? Just a preference, a direct return definitely would work in this case.

Java: How to find k values in the BST that are closest to the target?

I'm researching on how to find k values in the BST that are closest to the target, and came across the following implementation with the rules:
Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.
Note:
Given target value is a floating point.
You may assume k is always valid, that is: k ≤ total nodes.
You are guaranteed to have only one unique set of k values in the BST that are closest to the target. Assume that the BST is balanced.
And the idea of the implementation is:
Compare the predecessors and successors of the closest node to the target, we can use two stacks to track the predecessors and successors, then like what we do in merge sort, we compare and pick the closest one to the target and put it to the result list. As we know, inorder traversal gives us sorted predecessors, whereas reverse-inorder traversal gives us sorted successors.
Code:
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) {
val = x;
}
}
public class ClosestBSTValueII {
List<Integer> closestKValues(TreeNode root, double target, int k) {
List<Integer> res = new ArrayList<>();
Stack<Integer> s1 = new Stack<>(); // predecessors
Stack<Integer> s2 = new Stack<>(); // successors
inorder(root, target, false, s1);
inorder(root, target, true, s2);
while (k-- > 0) {
if (s1.isEmpty()) {
res.add(s2.pop());
} else if (s2.isEmpty()) {
res.add(s1.pop());
} else if (Math.abs(s1.peek() - target) < Math.abs(s2.peek() - target)) {
res.add(s1.pop());
} else {
res.add(s2.pop());
}
}
return res;
}
// inorder traversal
void inorder(TreeNode root, double target, boolean reverse, Stack<Integer> stack) {
if (root == null) {
return;
}
inorder(reverse ? root.right : root.left, target, reverse, stack);
// early terminate, no need to traverse the whole tree
if ((reverse && root.val <= target) || (!reverse && root.val > target)) {
return;
}
// track the value of current node
stack.push(root.val);
inorder(reverse ? root.left : root.right, target, reverse, stack);
}
public static void main(String args[]) {
ClosestBSTValueII cv = new ClosestBSTValueII();
TreeNode root = new TreeNode(53);
root.left = new TreeNode(30);
root.left.left = new TreeNode(20);
root.left.right = new TreeNode(42);
root.right = new TreeNode(90);
root.right.right = new TreeNode(100);
System.out.println(cv.closestKValues(root, 40, 2));
}
}
And my question is, what's the reason for having two stacks and how is in-order a good approach? What's the purpose of each? Wouldn't traversing it with one stack be enough?
And what's the point of having a reverse boolean, such as for inorder(reverse ? ...);? And in the case of if ((reverse && root.val <= target) || (!reverse && root.val > target)), why do you terminate early?
Thank you in advance and will accept answer/up vote.
The idea of the algorithm you found is quite simple. They do just in-order traversal of a tree from the place, where target should be inserted. They use two stacks to store predecessors and successors. Lets take the tree for example:
5
/ \
3 9
/ \ \
2 4 11
Let the target be 8. When all inorder method calls are finished, stacks will be: s1 = {2, 3, 4, 5}, s2 = {11, 9}. As you see, s1 contains all predecessors of target and s2 all successors of it. Moreover, both stacks are sorted in a way, that top of each stack is closer to target, than all other values in stack. As a result, we can easily find kclosest values, just by always comparing tops of the stacks, and popping the closest value until we have k values. The running time of their algorithm is O(n).
Now about your questions. I don't know, how to implement this algorithm using the only stack effectively. The problem with stack is that we have access only to the top of it. But it is extremely easy to implement the algorithm with one array. Lets just do usual in-order traversal of a tree. For my example we will get: arr = {2, 3, 4, 5, 9, 11}. Then lets place l and r indexes to the closest to target values from both of the sides: l = 3, r = 4 (arr[l] = 5, arr[r] = 9). What is left is just to always compare arr[l] and arr[r] and choose what to add to result (absolutely the same, as with two stacks). This algo also takes O(n) operations.
Their approach to the problem seems to me a bit too hard to understand in code, though it is rather elegant.
I'd like to introduce another approach to the problem with another running time. This algorithm will take O(k*logn) time, which is better for small k and worse for bigger ones than previous algorithm.
Lets also store in TreeNode class a pointer to parent node. Then we can find predecessor or successor of any node in tree easily in O(logn) time (if you don't know how). So, lets firstly find in the tree predecessor and successor of the target (without doing any traversals!). Then do the same as with stacks: compare predecessor\successor, choose the closest one, and for the closest go to its predecessor\successor.
I hope, I answered your questions and you understood my explanations. If not, feel free to ask!
The reason why you need two stack is that you must traverse the tree in two directions, and you must compare the current value of each stack with the value you're searching (you may end up having k values greater than the searched value, or k/2 greater and k/2 lower).
I think you should use stacks of TreeNodes rather that stacks of Integer; you could avoid recursion.
UPDATE:
I see two phases in the algorithm:
1) locate the closest value in the tree, that would simultaneously build the initial stack.
2) make a copy of the stack, move back one element, this will give you the second stack; then iterate at most k times: see which of the two elements on top of each stack is the closest to the searched value, add it to the result list, and move the stack forward or backward.
UPDATE 2: A little code
public static List<Integer> closest(TreeNode root, int val, int k) {
Stack<TreeNode> right = locate(root, val);
Stack<TreeNode> left = new Stack<>();
left.addAll(right);
moveLeft(left);
List<Integer> result = new ArrayList<>();
for (int i = 0; i < k; ++i) {
if (left.isEmpty()) {
if (right.isEmpty()) {
break;
}
result.add(right.peek().val);
moveRight(right);
} else if (right.isEmpty()) {
result.add(left.peek().val);
moveLeft(left);
} else {
int lval = left.peek().val;
int rval = right.peek().val;
if (Math.abs(val-lval) < Math.abs(val-rval)) {
result.add(lval);
moveLeft(left);
} else {
result.add(rval);
moveRight(right);
}
}
}
return result;
}
private static Stack<TreeNode> locate(TreeNode p, int val) {
Stack<TreeNode> stack = new Stack<>();
while (p != null) {
stack.push(p);
if (val < p.val) {
p = p.left;
} else {
p = p.right;
}
}
return stack;
}
private static void moveLeft(Stack<TreeNode> stack) {
if (!stack.isEmpty()) {
TreeNode p = stack.peek().left;
if (p != null) {
do {
stack.push(p);
p = p.right;
} while (p != null);
} else {
do {
p = stack.pop();
} while (!stack.isEmpty() && stack.peek().left == p);
}
}
}
private static void moveRight(Stack<TreeNode> stack) {
if (!stack.isEmpty()) {
TreeNode p = stack.peek().right;
if (p != null) {
do {
stack.push(p);
p = p.left;
} while (p != null);
} else {
do {
p = stack.pop();
} while (!stack.isEmpty() && stack.peek().right == p);
}
}
}
UPDATE 3
Wouldn't traversing it with one stack be enough?
And what's the point of having a reverse boolean, such as for
inorder(reverse ? ...);? And in the case of if ((reverse && root.val
<= target) || (!reverse && root.val > target)), why do you terminate
early?
I don't know where you got the solution you gave in you're question from, but to summarize, it builds two lists of Integer, one in straight order, one in reverse order. It terminates "early" when the searched value is reached. This solution sound very inefficient since it requires the traversal of the whole tree. Mine, of course, is much better, and it conforms to the given rules.

Is there a more elegant way to search the station index?

I work on a genetic algorithm for a robotic assembly line balancing problem (assigning assembly operations and robots to stations to minimize the cycle time for a given number of stations). The solution is represented by an ArrayList (configuration) which holds all the operations in the sequence assigned to different stations. Furthermore, I have two more ArrayLists (robotAssignment, operationPartition) which indicate where a new station starts and which robot is assigned to a station. For example, a solution candidate looks like this (configuration, robotAssignment, operationPartition from top to bottom):
Initial cycle time: 50.0
|2|7|3|9|1|5|4|6|8|10|
|2|1|3|2|
|0|2|5|7|
From this solution representation we know that operations 3, 9, and 1 are assigned to the second sation and robot 1 is used.
I need to keep track of the station an operation is assigned to. I tried a lot to store this in the Object Operation itself but I always ended up in problems and therefore I want to write a method that gives me the stations index of an operation.
Here is what I have coded so far:
// Get the station of an operation
public int getStation(Operation operation) {
int stationIndex = 0;
int position = configuration.indexOf(operation);
for (int i = 0; i < GA_RALBP.numberOfStations ; i++ ) {
if (i < GA_RALBP.numberOfStations - 1 && operationPartition.get(i) != null) {
if (isBetween(position, (int) operationPartition.get(i), (int) operationPartition.get(i + 1))) {
return stationIndex + 1;
} else {
stationIndex++;
}
}
else if (i >= GA_RALBP.numberOfStations - 1 && operationPartition.get(i) != null) {
if (isBetween(position, (int) operationPartition.get(i), configurationSize())) {
return stationIndex + 1;
}
}
}
return -1;
}
// Check if value x is between values left and right including left
public static boolean isBetween(int x, int left, int right) {
if (left <= x && x < right ) {
return true;
}
else {
return false;
}
}
However, this does not seem to be (a) very elegant and (b) if I have to do this for a large number of operations the runtime could become a problem. Has anoyone an idea how to solve this more efficiently?
Why not make the partitioning explicit (replaces your operationPartition) - something like:
Map<Integer, Integer> operationToStationMapping = new HashMap<>();
operationToStationMapping.put(2,0);
operationToStationMapping.put(7,0);
operationToStationMapping.put(3,2);
operationToStationMapping.put(9,2);
operationToStationMapping.put(1,2);
operationToStationMapping.put(5,5);
operationToStationMapping.put(6,7);
operationToStationMapping.put(8,-1);
operationToStationMapping.put(10,-1);
Then getStation() becomes:
getStation(int operation) {return operationToStationMapping.get(operation);}

Heapify function not working

I have been trying to write a recursive heapify method that turns an array of integers into a min-heap. The Main and Heap classes are shown below. Most of the array shown in Main is already a min-heap, but the subtree [11, 4, 5] is not a min-heap. However, the heapify function doesn't seem to reach that subtree. I can't figure out what the problem is, any help would be greatly appreciated.
public class Heap {
public Heap(int[] array) {
heap = array;
}
public void heapify() {
heapifyHelper(0);
}
public void heapifyHelper(int rootIndex) {
if(isLeafIndex(rootIndex)) {
return;
}
else {
int leftChildIndex = getLeftChildIndex(rootIndex);
int rightChildIndex = getRightChildIndex(rootIndex);
int leftChildValue = heap[leftChildIndex];
int rightChildValue = heap[rightChildIndex];
int rootValue = heap[rootIndex];
if(leftChildValue < rootValue && leftChildValue < rightChildValue) {
swap(rootIndex, leftChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
else if(rightChildValue < rootValue && rightChildValue < leftChildValue) {
swap(rootIndex, rightChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
}
}
public int getLeftChildIndex(int parentIndex) {
return 2 * parentIndex + 1;
}
public int getRightChildIndex(int parentIndex) {
return 2 * parentIndex + 2;
}
public int getParentIndex(int childIndex) {
if(childIndex == 0) {
throw new IllegalArgumentException("Cannot get the parent index of the root.");
}
else {
return (childIndex / 2) - 1;
}
}
public boolean isLeafIndex(int index) {
int leftIndex = getLeftChildIndex(index);
int rightIndex = getRightChildIndex(index);
if(leftIndex >= heap.length && rightIndex >= heap.length) {
return true;
}
else {
return false;
}
}
public void swap(int index1, int index2) {
int temp = heap[index1];
heap[index1] = heap[index2];
heap[index2] = temp;
}
public void printHeap() {
System.out.println(Arrays.toString(heap));
}
int[] heap;
}
public class Main {
public static void main(String[] args) {
int[] x = {0, 5, 2, 9, 11, 6, 12, 21, 32, 4, 5};
Heap heap = new Heap(x);
heap.printHeap();
heap.heapify();
heap.printHeap();
}
}
There are several problems in your heapifyHelper:
public void heapifyHelper(int rootIndex) {
if(isLeafIndex(rootIndex)) {
return;
}
else {
int leftChildIndex = getLeftChildIndex(rootIndex);
int rightChildIndex = getRightChildIndex(rootIndex);
int leftChildValue = heap[leftChildIndex];
int rightChildValue = heap[rightChildIndex];
What if leftChildIndex == heap.length - 1? Then rightChildValue will cause an ArrayIndexOutOfBoundsException.
int rootValue = heap[rootIndex];
if(leftChildValue < rootValue && leftChildValue < rightChildValue) {
swap(rootIndex, leftChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
else if(rightChildValue < rootValue && rightChildValue < leftChildValue) {
What if both children are equal, and smaller than the parent? In that case you don't swap at all.
swap(rootIndex, rightChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
}
}
And the reason why the subtree [11, 4, 5] isn't reached is because you only call heapifyHelper for the children if one of the children is smaller than the parent, but when you call heapifyHelper(1), the two children of the node 5 are 9 and 11, both larger than the root value. (Actually, you don't even call heapifyHelper(1), since heap[0]is already smaller than both its children.)
But rectifying that alone by unconditionally recurring (on the children that exist) doesn't make your heapify correct. If you recur from the root to the leaves, each value can bubble up at most one level. You must recur from the leaves to the root(1), and you need to sift the values down completely, not just one level.
If you only swap a value with one of its children, each position is considered at most twice. Once when comparing it to its parent, once when comparing it to its children. When you go from the root to the leaves, when you compare a position to its children, no position above it (no position with a smaller index, even) can ever be changed anymore.
So each value can bubble up at most one level. If the smallest element is below the direct children of root, root won't become the smallest element in the tree. If you start from the leaves (or rather the parents of the leaves), the values can bubble up as far as they need. But if you only swap a value with the smaller of its children (if that is smaller than the value), each value can still only bubble down one level, which still need not create a heap.
Let us consider the tree
7
/ \
/ \
2 6
/ \ / \
1 3 4 5
If you go from the root to the leaves, you swap 2 and 7 first, giving
2
/ \
/ \
7 6
/ \ / \
1 3 4 5
The top two levels are now a min-heap.
Then you treat the left subtree, and finally the right subtree, producing
2
/ \
/ \
1 4
/ \ / \
7 3 6 5
altogether. Now the bottom two levels are composed of min-heaps, but the heap property was destroyed in the level above. To make that a heap again, the 1 must be sifted up further (in this case, just one level).
If you go from the leaves to the root, you first treat the right subtree,
6
/ \
4 5
producing
4
/ \
6 5
for that, then the left subtree
2
/ \
1 3
producing
1
/ \
2 3
there. Both subtrees are now min-heaps. Altogether, you have
7
/ \
/ \
1 4
/ \ / \
2 3 6 5
Then you'd swap 7 and 1, producing
1
/ \
/ \
7 4
/ \ / \
2 3 6 5
Now the root is the smallest value, but the last swap destroyed the heap property of the left subtree. To make that a heap again, the 7 must be sifted down further.
So you need a siftDown method (and/or a siftUp method) that sifts a value down (up) as far as needed.
private void siftDown(int index) {
int leftChildIndex = getLeftChildIndex(index);
if (leftChildIndex >= heap.length) {
// a leaf, no further sifting down possible
return;
}
int rightChildIndex = getRightChildIndex(index);
if ((heap[leftChildIndex] < heap[index])
&& (rightChildIndex >= heap.length || heap[rightChildIndex] >= heap[leftChildIndex)) {
// left child is smallest or only, and smaller than parent
swap(index, leftChildIndex);
siftDown(leftChildIndex);
} else
// left child not smaller than parent, or right child exists and is smaller than parent
if (rightChildIndex < heap.length && heap[rightChildIndex] < heap[index]) {
swap(index, rightChildIndex);
siftDown(rightChildIndex);
}
// otherwise, this one has no smaller child, so no more sifting needed
}
Then a correct heapify would be
public void heapify() {
// last index that has a child:
int lastNonLeafIndex = heap.length/2 - 1;
for(int index = lastNonLeafIndex; index >= 0; --index) {
siftDown(index);
}
}
That works because if you have a (binary) tree where both of the subtrees are min-heaps, sifting down the root value constructs a min-heap:
If the root value is smaller than (or equal to) both its children, the entire tree is already a min-heap.
Otherwise, after the root value has been swapped with the smaller of its children (without loss of generality the left), the other subtree is unchanged, hence still a min-heap. And, since the left child was the smallest value in the left subtree before the swap, the value at the root is the smallest value in the entire tree after the swap. Swapping may have destroyed the min-heap property of the left child, though. But the left-left and the left-right subtrees have not been changed, so they are still min-heaps. And the new left subtree is smaller than the original tree, so by the induction hypothesis, sifting down its root value creates a min-heap from that. So after sifting down has finished, we have a tree with the smallest value at the root, both of whose subtrees are min-heaps, that is, a min-heap.
Since each leaf is trivially a min-heap, for each index processed in heapify, the subtree rooted at that index becomes a min-heap.
The alternative, using siftUp:
private void siftUp(int index) {
if (index == 0) return; // root, nothing to do
int parentIndex = getParentIndex(index); // see Note below
if (heap[index] < heap[parentIndex]) {
swap(index, parentIndex);
siftUp(parentIndex);
}
}
public void heapify() {
for(int index = 1; index < heap.length; ++index) {
siftUp(index);
}
}
The code for siftUp is much shorter than for siftDown, since only two nodes are involved here, and there is no need to check whether any child index falls outside the array. But the heapify is less efficient (see footnote (1)).
siftUp is the method used to insert a new value into a heap. So this one builds a heap by inserting all values (except the root value) into an existing min-heap [when siftUp(index) is called, the part of the array before index is already a min-heap].
Note: your getParentIndex is incorrect,
return (childIndex / 2) - 1;
says the parent of index 1 is -1, and the parent of index 3 is 0, correct is
return (childIndex - 1) / 2;
(1) Actually, you can proceed from the root to the leaves, if you sift each value up as far as needed. It's just more efficient to heapify going from the [parents of the] leaves to the root. If you go from the root to the leaves, at level k you have 2^k values that may need to bubble up k levels, which gives an O(n*log n) complexity for building the heap. If you proceed from the [parents of the] leaves upward, you have 2^(log n - 1 - k) values that may need to bubble down k levels, which gives a complexity of O(n) for building the heap.
So i think I figured out what the problem is.
Your heapify helper stops the minute you find a root where the root is smaller than leftChild and rightChild.
In running your case.. you reach a situation where root (5) is lesser than 11 and 9..But 11 is not heapified..
Many ways to fix this. That i leave to you.
EDIT
So heapify is ideally meant only to put the first element in the rootIndex in a correct place. Not to create a Heap.
If you want to create a correct Heap, you need to insert a new element and call heapify on every such insert.

Categories

Resources