leetcode question 437 why also apply DFS to children nodes? - java

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.

Related

Finding minimum depth of BST ... findHeight function won't work

Trying to solve this LC Easy: https://leetcode.com/problems/minimum-depth-of-binary-tree/
Which is to find the minimum depth (number of nodes on shortest path) of a tree.
I was able to create a "findheight" function which gives me the height of a tree.
My logic was to use findheight to find the height of both subtrees (left and right) of a root node, and then return the minimum between the two heights.
class Solution {
public int minDepth(TreeNode root) {
if(root == null){return 0;}
int left = findHeight(root.left);
int right = findHeight(root.right);
//unbalanced tree, only one subtree
if(left == 0 || right == 0){
return Math.max(left,right) + 1;
}
return Math.min(left,right) + 1 ;
}
public int findHeight(TreeNode root){
if(root == null){return 0;}
int left = findHeight(root.left);
int right = findHeight(root.right);
return Math.max(left,right) + 1;
}
}
It won't pass the test case:
[-9,-3,2,null,4,4,0,-6,null,-5]
Or:
Output:
4
Expected:
3
My thought process right now is that when I use "findHeight", I'm returning back the 'max' height per left and right subtree. In this test case, I should be returning back the minimum height.
I changed my code to "Math.min" in another iteration, but that doesn't work either.
Any ideas or theories why? So confused!! Should I just abandon this approach altogether?
Issue in current code
//unbalanced tree, only one subtree
if(left == 0 || right == 0){
return Math.max(left,right) + 1;
}
The above lines of code checks the imbalance only at root level. It does not recursively check imbalance at lower levels.
Check imbalance at every level
public int minDepth(final TreeNode node) {
if (node == null) {
return 0;
}
final int left = minDepth(node.left);
final int right = minDepth(node.right);
// if both paths exist, then return the minimum
if (node.left != null && node.right != null) {
return Math.min(left, right) + 1;
} else {
// if zero or one path exists return that path (so take maximum)
return Math.max(left, right) + 1;
}
}

Rewrite a C code in Java to construct full binary tree

I want to write a function to construct a full binary tree from a given preorder and postorder array. I found that link http://www.geeksforgeeks.org/full-and-complete-binary-tree-from-given-preorder-and-postorder-traversals/ which proposes the following C code :
struct node* constructTreeUtil (int pre[], int post[], int* preIndex,
int l, int h, int size)
{
// Base case
if (*preIndex >= size || l > h)
return NULL;
// The first node in preorder traversal is root. So take the node at
// preIndex from preorder and make it root, and increment preIndex
struct node* root = newNode ( pre[*preIndex] );
++*preIndex;
// If the current subarry has only one element, no need to recur
if (l == h)
return root;
// Search the next element of pre[] in post[]
int i;
for (i = l; i <= h; ++i)
if (pre[*preIndex] == post[i])
break;
// Use the index of element found in postorder to divide postorder array in
// two parts. Left subtree and right subtree
if (i <= h)
{
root->left = constructTreeUtil (pre, post, preIndex, l, i, size);
root->right = constructTreeUtil (pre, post, preIndex, i + 1, h, size);
}
return root;
}
// The main function to construct Full Binary Tree from given preorder and
// postorder traversals. This function mainly uses constructTreeUtil()
struct node *constructTree (int pre[], int post[], int size)
{
int preIndex = 0;
return constructTreeUtil (pre, post, &preIndex, 0, size - 1, size);
}
I tried to rewrite this code in Java. Here is my code :
private static TreeNode constructTree(int[] preorder, int[] postorder, Index index, int lowIndex, int highIndex){
// Base case
if (index.index >= preorder.length || lowIndex > highIndex){
return null;
}
// The first node in preorder traversal is root. So take the node at
// preIndex from preorder and make it root, and increment preIndex
TreeNode root = new TreeNode (preorder[lowIndex]);
index.index++;
// If the current subarry has only one element, no need to recur
if (lowIndex == highIndex){
return root;
}
// Search the next element of pre[] in post[]
int i = 0;
for (i = lowIndex; i <= highIndex; ++i)
if (preorder[i]== postorder[lowIndex])
break;
// Use the index of element found in postorder to divide postorder array in
// two parts. Left subtree and right subtree
if (i <= highIndex) {
root.left = constructTree(preorder, postorder, index, lowIndex, i);
root.right = constructTree(preorder, postorder, index, i + 1, highIndex);
}
return root;
}
//The main function to construct Full Binary Tree from given preorder and
//postorder traversals. This function mainly uses constructTreeUtil()
public static TreeNode constructTree (int preorder[], int postorder[]) {
return constructTree (preorder, postorder, new Index(), 0, preorder.length - 1);
}
But I got a continuous loop in the root node (it didn't pass to the other nodes which have to be its child). Can you help me please to see where is the error in my Java code?
I'm not really sure but I think that the error maybe comes from these lines :
int i = 0;
for (i = lowIndex; i <= highIndex; ++i)
if (preorder[i]== postorder[lowIndex])
break;
I didn't understand very well the correspond lines in the original C code. Especially in this part
Here are the bugs:
Line if (preorder[i]== postorder[lowIndex]) has two errors: the first is that you search in preorder instead of in postorder, and the second is that you use lowIndex instead of preIndex.
This line should be: if (preorder[index.index]== postorder[i])
Line TreeNode root = new TreeNode (preorder[lowIndex]); - lowIndex is used again instead of preIndex.
This line should be: TreeNode root = new TreeNode (preorder[index.index]);
Pay attention to the fact that this code would work only for full binary trees
Assuming that your code written in C works, then my guess is that for this part
// Search the next element of pre[] in post[]
int i = 0;
for (i = lowIndex; i <= highIndex; ++i)
if (preorder[i]== postorder[lowIndex])
break;
you'd want to use the same variables that you use in the C version. In this case, your if statement should be
if (preorder[index.index]== postorder[i])
First make your TreeNode into a class, since it is the java equivalent of a struct
public class TreeNode{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val){
this.val = val;
}
}
Then make your TreeUtil class
public class TreeUtil{
private static TreeNode constructTree(int[] preorder, int[] postorder, int index, int lowIndex, int highIndex){
// Base case
if (index >= preorder.length || lowIndex > highIndex){
return null;
}
// The first node in preorder traversal is root. So take the node at
// preIndex from preorder and make it root, and increment preIndex
TreeNode root = new TreeNode (preorder[index]);
index++;
// If the current subarry has only one element, no need to recur
if (lowIndex == highIndex){
return root;
}
// Search the next element of pre[] in post[]
for (int i = lowIndex; i <= highIndex; i++)
if (preorder[index]== postorder[i]){
// Use the index of element found in postorder to divide postorder array in
// two parts. Left subtree and right subtree
root.left = constructTree(preorder, postorder, index, lowIndex, i);
root.right = constructTree(preorder, postorder, index, i + 1, highIndex);
break;
}
}
return root;
}
//The main function to construct Full Binary Tree from given preorder and
//postorder traversals. This function mainly uses constructTreeUtil()
public static TreeNode constructTree (int preorder[], int postorder[]){
return constructTree (preorder, postorder, 0, 0, preorder.length - 1);
}
}
Errors in your code were if (preorder[i]== postorder[lowIndex] and TreeNode root = new TreeNode (preorder[lowIndex]); as mentioned by aviad. I changed your code for you to be slightly less confusing. Using the Index is a great way to confuse yourself especially since an int will work fine. Also ++i increments before you run the loop and isn't conventionally used in java and java lets you declare variables a part of your loop definition so I changed that for loop to be more what your are looking for.

Binary tree - find position in inorder traversal

I have a binary search tree where i have to implement a method called
int valueAtPosition(int x)
The problem is, that i need the position in an in order traversal.
To find the in order traversal i have this the following code, but i don't know how i count the recursive calls, to get the right position.
public void inOrderTraverseTree(Node root){
if(root != null){
inOrderTraverseTree(root.leftChild);
System.out.println(root);
inOrderTraverseTree(root.rightChild);
}
}
I think the other solutions are O(n). All you need for this is a count of the children for each node for O(log n).
When you insert a node, for each node you traverse you increase the counter on the traversed node by one.
You need to maintain these counters when deleting, rebalancing, etc which normally isn't difficult.
With this you can get the position of the node when inserted, find the position of a node by value or find a node by position.
To find a node by position is the same kind of binary traversal as for finding by value. If you want the item at position 1000 then you start at the root. No root, not item at that position. Then you look at the left child (you can do it in the other order too and switch ascending/descending), on the left if the left child exists the number of children on the left is 0 plus the count of the children on the left node. Let say in this scenario that the left exists and has 500 children. Then you know 1000 can't be left because there aren't enough items on the left, so it must be right. You can repeat this also checking for bounds all the way down.
For simple O(n) in order traversal if you have a global counter you just increase it only after traversing the left. That should do the same as a depth first search. No need for decreasing and increasing counters or pushing and popping on a stack. You can also have your functions return a count.
public int inOrderTraverseTree(Node root){
if(root == null)
return 0;
int count = inOrderTraverseTree(root.leftChild);
count++;
count += inOrderTraverseTree(root.rightChild);
return count;
}
This approach only becomes annoying if you want to return the node as well.
You can of course replace a recursive function with your own stack but this is a rarely needed performance optimisation and you'll be far better off with the O(log n) solution if you need performance than an optimised custom stack based solution.
You can also use a counter in the recursive approach. However, you can't simply pass an int counter argument - you need all calls to see the "same" counter, so you will have to wrap it in a class (or, as in this case, an inner class):
public static class Counter {
private int value;
public Counter(int initialValue) { value = initialValue; }
public boolean decrement() { value--; return value == 0; }
public boolean expired() { return value <= 0; }
}
public Node inOrderTraverseTree(Node root, Counter counter){
if (root != null && ! counter.expired()) {
Node left = inOrderTraverseTree(root.leftChild, counter);
if (left != null) {
return left;
} else if (counter.decrement()) {
return root;
} else {
return inOrderTraverseTree(root.rightChild, counter);
}
} else {
return null;
}
}
To find the 9th node in-order (using 1-based indexing), you would call this as
Node the9th = inOrderTraverseTree(root, new Counter(9));
If there is no 9th node, it would return null. If you want to use 0-based indexing instead, change { value--; return value == 0; } to { return value-- == 0; }
The iterative in-order traversal approach makes this pretty easy. Increment a counter whenever a node is popped from the stack. When the counter is equal to x, return the value of the node.
Integer valueAtPosition(int x, Node root) {
int count = 0;
List<Node> stack = new ArrayList<>();
Node node = root;
while (!stack.isEmpty() || node != null) {
if (node != null) {
stack.add(node);
node = node.leftChild;
} else {
node = stack.pop();
if (count == x) {
return node.value;
}
count++;
node = node.rightChild;
}
}
return null;
}
Recursive version requires passing a mutable wrapper for a counter like so:
public class Counter {
int count = 0;
}
public void inOrderTraverseTree(Node root, int index, Counter counter){
if(root == null || counter.count > index) {
return;
}
inOrderTraverseTree(root.leftChild);
if (counter.count == index) {
System.out.println(root);
}
counter.count = counter.count + 1;
inOrderTraverseTree(root.rightChild);
}
Following is recursive in-order traversal approach: (in c++)
bool valueAtPositionUtil(struct treeNode *root, int &currIndex, int i, int &value) {
if(root != NULL) {
if(valueAtPositionUtil(root->left, currIndex, i, value)) {
return true;
}
if(currIndex == i) {
value = root->data;
return true;
}
currIndex++;
if(valueAtPositionUtil(root->right, currIndex, i, value)) {
return true;
}
}
return false;
}
int ValueAtPosition(int i, struct treeNode *root) {
int value = 0;
int currIndex = 0;
if(valueAtPositionUtil(root, currIndex, i, value)) {
return value;
}
//index out of bound
// you can return according your problem
return -1;
}

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

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

How to calculate the depth of a binary search tree

I would like to calculate the summation of the depths of each node of a Binary Search Tree.
The individual depths of the elements are not already stored.
Something like this:
int countChildren(Node node)
{
if ( node == null )
return 0;
return 1 + countChildren(node.getLeft()) + countChildren(node.getRight());
}
And to get the sum of the depths of every child:
int sumDepthOfAllChildren(Node node, int depth)
{
if ( node == null )
return 0; // starting to see a pattern?
return depth + sumDepthOfAllChildren(node.getLeft(), depth + 1) +
sumDepthOfAllChildren(node.getRight(), depth + 1);
}
Now for a hopefully informative explanation in case this is homework. Counting the number of nodes is quite simple. First of all, if the node isn't a node (node == null) it returns 0. If it is a node, it first counts its self (the 1), plus the number of nodes in its left sub-tree plus the number of nodes in its right sub-tree. Another way to think of it is you visit every node via BFS, and add one to the count for every node you visit.
The Summation of depths is similar, except instead of adding just one for each node, the node adds the depth of its self. And it knows the depth of its self because its parent told it. Each node knows that the depth of it's children are it's own depth plus one, so when you get the depth of the left and right children of a node, you tell them their depth is the current node's depth plus 1.
And again, if the node isn't a node, it has no depth. So if you want the sum of the depth of all the root node's children, you pass in the root node and the root node's depth like so: sumDepthOfAllChildren(root, 0)
Recursion is quite useful, it's just a very different way of thinking about things and takes practice to get accustomed to it
int maxDepth(Node node) {
if (node == null) {
return (-1); // an empty tree has height −1
} else {
// compute the depth of each subtree
int leftDepth = maxDepth(node.left);
int rightDepth = maxDepth(node.right);
// use the larger one
if (leftDepth > rightDepth )
return (leftDepth + 1);
else
return (rightDepth + 1);
}
}
This solution is even more simpler.
public int getHeight(Node root)
{
if(root!=null)
return 1+ Math.max(getHeight(root.leftchild),getHeight(root.rightchild));
else
return 0;
}
For any given tree, the number of nodes is 1 for the root plus the number of nodes in the left subtree plus the number of nodes in the right subtree :)
Details, like making sure there actually is a left or right subtree, are "left to the reader".
private static int getNumberOfNodes(Node node) {
if (node == null) {
return 0;
}
return 1 + getNumberOfNodes(node.left) + getNumberOfNodes(node.right);
}
public int countNodes(Node root)
{
// Setup
// assign to temps to avoid double call accessors.
Node left = root.getLeft();
Node right = root.getRight();
int count = 1; // count THIS node.
// count subtrees
if (left != null) count += countNodes(left);
if (right != null) count += countNodes(right);
return count;
}
public class Node {
private Node left;
private Node right;
public int size() { return 1+ (left==null?0:left.size())+ (right==null?0:right.size());}
}
int depth(treenode *p)
{
if(p==NULL)return(0);
if(p->left){h1=depth(p->left);}
if(p=>right){h2=depth(p->right);}
return(max(h1,h2)+1);
}
public int numberOfNodes()
{
// This node.
int result = 1;
// Plus all the nodes from the left node.
Node left = getLeft();
if (left != null)
result += left.numberOfNodes();
// Plus all the nodes from the right node.
Node right = getRight();
if (right != null)
result += right.numberOfNodes();
return result;
}
public int getDepthHelper( TreeNode< T > node ) {
int treeHeightLeft;
int treeHeightRight;
//get height of left subtree
if( node.leftNode == null )
treeHeightLeft = 1;
else {
treeHeightLeft = getDepthHelper( node.leftNode) + 1;
}
//get height of right subtree
if( node.rightNode == null )
treeHeightRight = 1;
else {
treeHeightRight = getDepthHelper( node.rightNode) + 1;
}
return Math.max(treeHeightLeft, treeHeightRight);
}

Categories

Resources