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

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;
}
}

Related

Checking a tree to be a BST

Here is my attempt to check whether a tree is a BST or not:
public boolean isBST() {
return isBSTRecursively(this.root, new Max());
}
class Max {
int value;
}
private boolean isBSTRecursively(Node node, Max max) {
if (node == null) return true; // to handle null root
// to handle scenario when both child nodes are absent
if(node.getLeft() == null && node.getRight() == null) {
max.value = node.getValue();
return true;
}
// if left child is absent, we only investigate right subtree
if(node.getLeft() == null) {
Max rightMax = new Max();
boolean isRightBST = isBSTRecursively(node.getRight(), rightMax);
max.value = Math.max(node.getValue(), rightMax.value);
if(isRightBST && node.getValue() < rightMax.value) {
return true;
} else {
return false;
}
} else {
Max leftMax = new Max();
boolean isLeftBST = isBSTRecursively(node.getLeft(), leftMax);
// if right child is absent, we only investigate left subtree
if(node.getRight() == null) {
max.value = Math.max(node.getValue(), leftMax.value);
if(isLeftBST && node.getValue() > leftMax.value) {
return true;
} else {
return false;
}
} else {
// we investigate both left and right subtrees
Max rightMax = new Max();
boolean isRightBST = isBSTRecursively(node.getRight(), rightMax);
max.value = Math.max(Math.max(leftMax.value, node.getValue()), rightMax.value);
if(isLeftBST && isRightBST && leftMax.value < node.getValue() && node.getValue() < rightMax.value) {
return true;
} else {
return false;
}
}
}
Code works fine as tested with multiple test cases.
But I am not sure if this is a good, clean approach.
Recursive method is big it seems. I am dealing with scenarios like null left node, null right node, node itself null, both child nodes null etc. separately. I guess they all can be handled in a much smaller, and cleaner way.
Moreover, I am always more inclined towards iterative approach(I generally find it better to visualize). Would that be better here (given it can be done iteratively)?
Any suggestions?
A cleaner recursive approach
You could use a bounded approach, i.e. have two variables for every recursion: min and max.
Initially min = INT_MIN and max = INT_MAX
if node = NULL then return True because an empty BST is a BST
else check if node.val < min or node.val > max if this condition is True then tree is not a BST, return False Notice : the strict inequality > and < are used as BST doesn't allow duplicate elements.
recurse for left : recur(node.left) with min remaining the same and max = node.val - 1 because the left subtrees should have values not greater than node.val - 1.
The max cannot be node.val because BST cannot have duplicate elements.
Store the boolean return value in say left
recurse for right : recur(node.right) with min = node.val + 1 and max remaining the same.
The right subtrees should have values not less than node.val + 1.
Store the boolean return value in say right
return left && right
#Aditya gave the ingredients of the more elegant solution.
It is generally not forbidden for a binary search tree to have duplicate values, so there should no be reduction of the "window" with 1.
Here is suggested code:
public boolean isBST() {
return isBSTRecursively(this.root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
private boolean isBSTRecursively(Node node, int min, int max) {
return node == null
|| node.getValue() >= min && node.getValue() <= max
&& isBSTRecursively(node.getLeft(), min, node.getValue())
&& isBSTRecursively(node.getRight(), node.getValue(), max);
}

Why is recursion causing the count to return 2 instead of 4?

I am trying to do the Balanced Tree question on Leetcode where you return true only if height of left subtree - height of right subtree <= 1.
Why is the depth of the left subtree returning a 2 when it should return 4? Is there something I am interpreting wrongly? I attached a picture of the tree at the bottom.
Input: [1,2,2,3,3,null,null,4,4,null,null,5,5]
Output: True (because left subtree is returning 2 instead of 4)
Expected Output: False
Print Statements:
left subtree: 2
right subtree: 1
result: 1 (left subtree - right subtree)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
// 1 2 2 3 3 4 4
//
if (root == null) return true;
System.out.println("left subtree: " + findDepth(root.left,1));
System.out.println("right subtree: " + findDepth(root.right,1));
System.out.println("result: " + Math.abs(findDepth(root.left,1) - findDepth(root.right, 1)));
if ( Math.abs(findDepth(root.left,1) - findDepth(root.right, 1)) <= 1) return true;
return false;
}
public static int findDepth(TreeNode root, int count) {
if (root == null) return count;
if (root.left != null) {
count++;
findDepth(root.left, count);
}
if(root.left == null && root.right == null) return count;
return count;
}
}
Image of Binary Tree
The reason why you get 2 is because when you recurse, the recursive call is not incrementing the count variable that you pass in. Instead, it increments its own copy of it. Java is pass by value.
if (root.left != null) {
count++;
// the call below will not change "count" at all
findDepth(root.left, count);
// it will only change its own copy
}
Therefore, the recursive call practically does nothing. You are not even using its return value. Its return value is actually the modified copy of count that you want count to be set to, so to fix this, set count to the return value of findDepth:
value = findDepth(root.left, count);
This will give you the expected 4, but your findDepth should also check the right subtree, and can be improved in other ways. For example, you don't actually need a count argument.
public static int findDepth(TreeNode root) {
if (root == null) return 0;
return 1 + Math.max(findDepth(root.left), findDepth(root.right));
}
Because you are only counting the depth of the left side of the tree in findDepth methof by applying condition
if (root.left != null) {
count++;
findDepth(root.left, count);
}
You can modify your method like this
public static int findDepth(TreeNode root, int count) {
if (root == null) return count;
return Math.max(findDepth(root.left, count+1),findDepth(root.right, count+1));
}

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;
}

Calculating Max Imbalance of Binary Search Tree

I am currently coding a recursive method to return the max imbalance on the whole of a Binary Search Tree. I've very new to recursive programming so it's quite difficult to wrap my head around. The tree I have built has an Imbalance of 1 but my method only returns 0. I'm sure my logic here is flawed.
I'm 100% sure its running " (root == null){ return 0;} " in every step of the method. I tried removing it and defining it further and it continues to do the same.
This is my current method:
public int getMaxImbalance(){
return Math.abs(getMaxImbalance(root));
}
public int getMaxImbalance (TreeNode<E> root){
if (root == null){
return 0;
}else if(root.left != null && root.right == null){
return 1 + getMaxImbalance(root.left) + getMaxImbalance(root.right);
//adds 1 left is true and right is false
}else if(root.left == null && root.right != null){
return -1 + getMaxImbalance(root.left) + getMaxImbalance(root.right);
//adds -1 left is false and right is true
}
return getMaxImbalance(root.left) + getMaxImbalance(root.right);
//calls itself if both fields are null;
}
The logic in your code seems wrong: the max imbalance of a node is not the sum of the max imbalance of its child(ren). Rather, the max imbalance should be the abs of the difference of the height of its child(ren) (if one of them is empty the max imbalance of that node is just 0, so the max imbalance of the current node depends entirely on it's only child).

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