Summing binary tree producing unexpected results - java

Trying to sum all nodes in a BST of Integers
The method is passed 0, but when it transitions from the left sub tree to right sub tree, the sum seems to decrease. Any help would be appreciated
The method is passed the root and a counter initialized to 0
public static int sumTree(TreeNode root,int sum) {
if (root != null) {
System.out.println("current value: " + root.getValue());
sum += (Integer) root.getValue();
System.out.println(sum);
sumTree(root.getLeft(),sum);
sumTree(root.getRight(),sum);
}
return sum;
}

sumTree(root.getLeft(),sum);
sumTree(root.getRight(),sum);
Just looking at these calls in isolation, they don't do anything. Their return values are being lost, and modifications to the recursive copies of sum don't affect the caller's sum; they're different variables.
public static int sumTree(TreeNode root) {
if (root == null) {
return 0;
}
System.out.println("current value: " + root.getValue());
int sum = (Integer) root.getValue();
System.out.println(sum);
sum += sumTree(root.getLeft());
sum += sumTree(root.getRight());
return sum;
}
The fix is to add the return values of the two recursive calls to sum. There's no need to have sum as a parameter: the sum of a sub-tree is independent of the rest of the tree above it.

Related

leetcode question 437 why also apply DFS to children nodes?

I am working on Leetcode question 437 Path Sum III, and solving it use DFS on java:
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public static int pathSum(TreeNode root, int sum) {
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
public static int dfs(TreeNode root, int sum) {
if (root == null) return 0;
int count = 0;
if (root.val == sum) count++;
count += dfs(root.left, sum - root.val);
count += dfs(root.right, sum - root.val);
return count;
}
In the return statement of pathSum() method, why we need "dfs(root, sum)+dfs(root.left, sum)+dfs(root.right, sum)", not simply "dfs(root, sum)(this one returns wrong answer)"?
Someone explains that is because "The path does not need to start or end at the root or a leaf "(from lc437). If so, then why we only need to also only check root's children, not also the children of root's children?
To avoid NullPointerException you need to make a small change in pathSum:
public static int pathSum(TreeNode root, int sum) {
if( root == null) return 0;
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
Consider the given tree:
Now let's transverse the tree from the root node searching for a path with a length of 8.
This can do it by omitting +pathSum(root.left, sum)+pathSum(root.right, sum); from pathSum:
public static int pathSum(TreeNode root, int sum) {
if( root == null) return 0;
//check root only
return dfs(root, sum);//+pathSum(root.left, sum)+pathSum(root.right, sum);
}
This return 0 because there is no path, starting at the root, with the length of 0.
So now we want to check the sub trees. Is there any path with a length of 8 starting at root.right ? We can do it like so:
public static int pathSum(TreeNode root, int sum) {
if( root == null) return 0;
//check root, check root.right and return the sum
return dfs(root, sum) + pathSum(root.right, sum) ;//+pathSum(root.left, sum);
}
This should return 1 because there is one path starting atroot.right with the length of 8: -3 -> 11
I hope this clarifies why we need to check root as well as left and right for the complete result.
Side note: you can get the same result by checking all tree node in a non-recursive manner. For example:
Stack<TreeNode> stack = new Stack<>();
stack.add(root);
int count = 0;
while (! stack.isEmpty()){
TreeNode node = stack.pop();
count += dfs(node,8);
if(node != null) {
stack.add(node.left);
stack.add(node.right);
}
}
System.out.println(count);
Because by going left and right on the tree we will traverse it. We have to traverse the tree in order to find the path sum. If you only go to root then you will not move in the tree thus resulting in the wrong answer.
public static int pathSum(TreeNode root, int sum) {
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
What this does is it treats each of the nodes as the root of a subtree on which it calculates the path and by calculating the sum of the path of the smaller trees you will obtain the sum of the paths of the larger tree.
I hope that this helps.

Recursively finding the average of even numbers in an array

I'm trying to find the average of all even numbers in an array using recursion and I'm stuck.
I realize that n will have to be decremented for each odd number so I divide by the correct value, but I can't wrap my mind around how to do so with recursion.
I don't understand how to keep track of n as I go, considering it will just revert when I return.
Is there a way I'm missing to keep track of n, or am I looking at this the wrong way entirely?
EDIT: I should have specified, I need to use recursion specifically. It's an assignment.
public static int getEvenAverage(int[] A, int i, int n)
{
// first element
if (i == 0)
if (A[i] % 2 == 0)
return A[0];
else
return 0;
// last element
if (i == n - 1)
{
if (A[i] % 2 == 0)
return (A[i] + getEvenAverage(A, i - 1, n)) / n;
else
return (0 + getEvenAverage(A, i - 1, n)) / n;
}
if (A[i] % 2 == 0)
return A[i] + getEvenAverage(A, i - 1, n);
else
return 0 + getEvenAverage(A, i - 1, n);
}
In order to keep track of the number of even numbers you have encountered so far, just pass an extra parameter.
Moreover, you can also pass an extra parameter for the sum of even numbers and when you hit the base case you can return the average, that is, sum of even numbers divided by their count.
One more thing, your code has two base cases for the first as well as last element which is unneeded.
You can either go decrementing n ( start from size of array and go till the first element ), or
You can go incrementing i starting from 0 till you reach size of array, that is, n.
Here, is something I tried.
public static int getEvenAvg(int[] a, int n, int ct, int sum) {
if (n == -1) {
//make sure you handle the case
//when count of even numbers is zero
//otherwise you'll get Runtime Error.
return sum/ct;
}
if (a[n]%2 == 0) {
ct++;
sum+=a[n];
}
return getEvenAvg(a, n - 1, ct, sum);
}
You can call the function like this getEvenAvg(a, size_of_array - 1, 0, 0);
Example
When dealing with recursive operations, it's often useful to start with the terminating conditions. So what are our terminating conditions here?
There are no more elements to process:
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
... okay, now how do we reduce the number of elements to process? We should probably increment index?
index++;
... oh, but only when going to the next level:
getEvenAverage(elements, index++, sum, count);
Well, we're also going to have to add to sum and count, right?
sum += a[index];
count++;
.... except, only if the element is even:
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
... and that's about it:
static int getEvenAverage(int[] elements, int index, int sum, int count) {
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
return getEvenAverage(elements, index + 1, sum, count);
}
... although you likely want a wrapper function to make calling it prettier:
static int getEvenAverage(int[] elements) {
return getEvenAverage(elements, 0, 0, 0);
}
Java is not a good language for this kind of thing but here we go:
public class EvenAverageCalculation {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
System.out.println(getEvenAverage(array));
}
public static double getEvenAverage(int[] values) {
return getEvenAverage(values, 0, 0);
}
private static double getEvenAverage(int[] values, double currentAverage, int nrEvenValues) {
if (values.length == 0) {
return currentAverage;
}
int head = values[0];
int[] tail = new int[values.length - 1];
System.arraycopy(values, 1, tail, 0, tail.length);
if (head % 2 != 0) {
return getEvenAverage(tail, currentAverage, nrEvenValues);
}
double newAverage = currentAverage * nrEvenValues + head;
nrEvenValues++;
newAverage = newAverage / nrEvenValues;
return getEvenAverage(tail, newAverage, nrEvenValues);
}
}
You pass the current average and the number of even elements so far to each the recursive call. The new average is calculated by multiplying the average again with the number of elements so far, add the new single value and divide it by the new number of elements before passing it to the next recursive call.
The way of recreating new arrays for each recursive call is the part that is not that good with Java. There are other languages that have syntax for splitting head and tail of an array which comes with a much smaller memory footprint as well (each recursive call leads to the creation of a new int-array with n-1 elements). But the way I implemented that is the classical way of functional programming (at least how I learned it in 1994 when I had similar assignments with the programming language Gofer ;-)
Explanation
The difficulties here are that you need to memorize two values:
the amount of even numbers and
the total value accumulated by the even numbers.
And you need to return a final value for an average.
This means that you need to memorize three values at once while only being able to return one element.
Outline
For a clean design you need some kind of container that holds those intermediate results, for example a class like this:
public class Results {
public int totalValueOfEvens;
public int amountOfEvens;
public double getAverage() {
return totalValueOfEvens + 0.0 / amountOfEvens;
}
}
Of course you could also use something like an int[] with two entries.
After that the recursion is very simple. You just need to recursively traverse the array, like:
public void method(int[] values, int index) {
// Abort if last element
if (index == values.length - 1) {
return;
}
method(array, index + 1);
}
And while doing so, update the container with the current values.
Collecting backwards
When collecting backwards you need to store all information in the return value.
As you have multiple things to remember, you should use a container as return type (Results or a 2-entry int[]). Then simply traverse to the end, collect and return.
Here is how it could look like:
public static Results getEvenAverage(int[] values, int curIndex) {
// Traverse to the end
if (curIndex != values.length - 1) {
results = getEvenAverage(values, curIndex + 1);
}
// Update container
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
// Return accumulated results
return results;
}
Collecting forwards
The advantage of this method is that the caller does not need to call results.getAverage() by himself. You store the information in the parameters and thus be able to freely choose the return type.
We get our current value and update the container. Then we call the next element and pass him the current container.
After the last element was called, the information saved in the container is final. We now simply need to end the recursion and return to the first element. When again visiting the first element, it will compute the final output based on the information in the container and return.
public static double getEvenAverage(int[] values, int curIndex, Results results) {
// First element in recursion
if (curIndex == 0) {
// Setup the result container
results = new Results();
}
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
int returnValue = 0;
// Not the last element in recursion
if (curIndex != values.length - 1) {
getEvenAverage(values, curIndex + 1, results);
}
// Return current intermediate average,
// which is the correct result if current element
// is the first of the recursion
return results.getAverage();
}
Usage by end-user
The backward method is used like:
Results results = getEvenAverage(values, 0);
double average results.getAverage();
Whereas the forward method is used like:
double average = getEvenAverage(values, 0, null);
Of course you can hide that from the user using a helper method:
public double computeEvenAverageBackward(int[] values) {
return getEvenAverage(values, 0).getAverage();
}
public double computeEvenAverageForward(int[] values) {
return getEvenAverage(values, 0, null);
}
Then, for the end-user, it is just this call:
double average = computeEvenAverageBackward(values);
Here's another variant, which uses a (moderately) well known recurrence relationship for averages:
avg0 = 0
avgn = avgn-1 + (xn - avgn-1) / n
where avgn refers to the average of n observations, and xn is the nth observation.
This leads to:
/*
* a is the array of values to process
* i is the current index under consideration
* n is a counter which is incremented only if the current value gets used
* avg is the running average
*/
private static double getEvenAverage(int[] a, int i, int n, double avg) {
if (i >= a.length) {
return avg;
}
if (a[i] % 2 == 0) { // only do updates for even values
avg += (a[i] - avg) / n; // calculate delta and update the average
n += 1;
}
return getEvenAverage(a, i + 1, n, avg);
}
which can be invoked using the following front-end method to protect users from needing to know about the parameter initialization:
public static double getEvenAverage(int[] a) {
return getEvenAverage(a, 0, 1, 0.0);
}
And now for a completely different approach.
This one draws on the fact that if you have two averages, avg1 based on n1 observations and avg2 based on n2 observations, you can combine them to produce a pooled average:
avgpooled = (n1 * avg1 + n2 * avg2) / (n1 + n2).
The only issue here is that the recursive function should return two values, the average and the number of observations on which that average is based. In many other languages, that's not a problem. In Java, it requires some hackery in the form of a trivial, albeit slightly annoying, helper class:
// private helper class because Java doesn't allow multiple returns
private static class Pair {
public double avg;
public int n;
public Pair(double avg, int n) {
super();
this.avg = avg;
this.n = n;
}
}
Applying a divide and conquer strategy yields the following recursion:
private static Pair getEvenAverage(int[] a, int first, int last) {
if (first == last) {
if (a[first] % 2 == 0) {
return new Pair(a[first], 1);
}
} else {
int mid = (first + last) / 2;
Pair p1 = getEvenAverage(a, first, mid);
Pair p2 = getEvenAverage(a, mid + 1, last);
int total = p1.n + p2.n;
if (total > 0) {
return new Pair((p1.n * p1.avg + p2.n * p2.avg) / total, total);
}
}
return new Pair(0.0, 0);
}
We can deal with empty arrays, protect the end-user from having to know about the book-keeping arguments, and return just the average by using the following public front-end:
public static double getEvenAverage(int[] a) {
return a.length > 0 ? getEvenAverage(a, 0, a.length - 1).avg : 0.0;
}
This solution has the benefit of O(log n) stack growth for an array of n items, versus O(n) for the various other solutions that have been proposed. As a result, it can deal with much larger arrays without fear of a stack overflow.

Recursive function responding different value

I wrote a java recursive function to get sum of a number as follows, and the sum should be single digit as well.the problem i am facing here is it should return the else part at the end where as it is giving the after if else condition return statement:
static int recSum(int n){
int sum = 0;
while(n!=0){
sum += n%10;
n = n/10;
}
if(sum>9) {
recSum(sum);
}
else {
return sum;
}
return sum ;
}
Let us say n = 12345 so at the end it needs to return 5 where as it is returning 14. However it is going to the else part but the correct value is not returning. I got the solution with the ternary operator without else loop. but would like to what is the reason for this i am getting the previous sum of 14 rather 5 (5 comes from 14 = 1+4)
Appreciate the response on this
The change you should do is fairly simple: you should remove the last return statement and just return the result of recursive call:
static int recSum(int n){
int sum = 0;
while(n!=0){
sum += n%10;
n = n/10;
}
if(sum>9) {
return recSum(sum);
}
else {
return sum;
}
}
When this function gets to the if statement and calls the function again the 15 is saved on the stack until the current call is finished, when the current call is finished the previous answer was 15 so it's returning that because you dont modify it in anyway after it gets returned.
This is an iterative way (NOT a good way to build recursion in your program)
while (n != 0) {
sum += n % 10;
n = n / 10;
}
This is the correct recursive way and works even for 0 and negative numbers.
static int recSum(int n) {
int sum = 0;
sum = sum + (n % 10);
n = n / 10;
if (n != 0) {
return sum + recSum(n);
} else {
return sum;
}
}

Count total number of edges in binary tree

I need to write one method to compute the total number of edges in a binary tree. I was trying recursion because it can be computed based on the number of nodes - 1, but wasn't sure how to subtract one at the end of recursion. Because of that, I am trying to update a variable "count" and just subtract one at the end. I was wondering if this is the best approach, or if I should try another way.
public int numOfEdges(Node v){
int count;
if(isLeaf(v){
count = 0;
}
else{
count = 1 + numOfEdges(left(v)) + numOfEdges(right(v));
}
return count - 1;
}
I think this might be easiest to accomplish by just writing two different methods, a common technique when using recursion:
private int numNodesIn(Node v) {
if (v == null) return 0;
return 1 + numNodesIn(v.left) + numNodesIn(v.right);
}
public int numEdgesIn(Node v) {
return v == null? 0 : numNodesIn(v) - 1;
}

Binary Tree and Recursion in Java

I have a Node class as follows:
public class Node {
private int value;
private Node leftNode;
private Node rightNode;
public Node(Node leftNode, Node rightNode, int value){
this.leftNode = leftNode;
this.rightNode = rightNode;
this.value = value;
}
//Getter and Setter methods for these variables are defined here
}
This Node class is used to create a Binary tree. I am writing a recursive function in JAVA to calculate the average of all the nodes. The code I have written below does not give correct answer. I think this is because the values of the parameters average and nodeCount are passed, and not the references.
public double treeAverage(Node node, double average, int nodeCount){
nodeCount ++;
if(node == null) return Double.MAX_VALUE;
if(node.getLeftNode()==null && node.getRightNode()==null){
average = ( average + node.getValue() )/nodeCount;
}
if(node.getLeftNode()!=null){
average = treeAverage(node.getLeftNode(), average, nodeCount);
}
if(node.getRightNode()!=null){
average = treeAverage(node.getRightNode(), average, nodeCount);
}
return average;
}
What would be a correct way to right this recursive function in Java? (in C I can pass the references to those parameters). Please correct me if I am wrong.
I guess you could use a helper method. Something like this (I haven't compiled this code, should be taken as hint)
private static long count = 0L;
private static long sum = 0L;
public static int treeAverageHelper(Node node){
if(node == null) return 0;
count ++;
return node.val + treeAverageHelper(node.left) + treeAverageHelper(node.right);
}
public static double treeAvg(Node n){
sum = treeAverageHelper(n);
if (count == 0)
return 0D;
else
return (double)sum/count;
}
The helper, goes through the tree aggregating and counting. And finally you divide the two.
I'm not a fan of these two parts:
if(node == null) return Double.MAX_VALUE;
if(node.getLeftNode()==null && node.getRightNode()==null){
average = ( average + node.getValue() )/nodeCount;
}
For the first statement, why would the average of an empty tree be the highest possible Double? Seems arbitrary. It would be simpler to say it doesn't exist, Double.NaN, or even 0.0 - since the tree has zero elements in it.
For the second statement, you have the logic correct in that if both the children are null, you get back its value. However, you're going to be wrecking your average along the way - if you have twelve nodes, and you're on your third, then your average values will be different when you move to your fourth node.
Move nodeCount to a higher scope, and don't worry about computing the actual average until you've counted the sum of all nodes from the recursive call. Lastly, pass along the total sum of your nodes as you go along.
I think there is a problem in average calculation.
According to your code,
if node have no left child and no right child, you added average + node.getValue() and divide this result by nodeCount.
In fact,
average is total value divided by count.
That means you should get total node value first and divide this by nodeCount.
You need to define a class, such as
class RecursionValues {
int nodeCount;
double average;
}
... and then in your recursive call you pass an instance of this class and modify its fields.
This is how I was able to get it working. Please let me know if it is not a good way.
private double sum = 0;
private int nodeCount = 0;
public double treeAverage(Node node){
if(node == null) return Double.NaN; //Null check
sum = treeSum(node);
double average = (sum/nodeCount);
// before returning, reset the sum and nodeCount, so that same object can use the same function starting with correct/zero values of sum and nodeCount
sum = 0; nodeCount = 0;
return average;
}
public double treeSum(Node node){
nodeCount ++; //update the nodeCount
sum = sum + node.getValue(); //update the sum to include this node
/* If the current node has children, recurse*/
if(node.getLeftNode()!=null){
sum = treeSum(node.getLeftNode());
}
if(node.getRightNode()!=null){
sum = treeSum(node.getRightNode());
}
return sum;
}

Categories

Resources