I am following a leet code task which is called Binary tilt. The link to the question is here: https://leetcode.com/problems/binary-tree-tilt/description/
I was stuck on the question so had a look at the solution and I was hoping someone could interpret parts of the below solution for me:
public class Solution {
int result = 0;
public int findTilt(TreeNode root) {
postOrder(root);
return result;
}
private int postOrder(TreeNode root) {
if (root == null) return 0;
int left = postOrder(root.left);
int right = postOrder(root.right);
result += Math.abs(left - right);
return left + right + root.val;
}
}
integers left and right are set to a value every time the recursion happens. What I don’t understand is where this value comes from as in I thought the root.val method would need to be used. Can you explain this in layman terms?
When the method postOrder returns left+right+rootval where is the method returned to? How is it used with the recursive method?
I think what is confusing you is that calculating sum of left and right subtree and calculating tilt for each node is combined in one method. So, I simplified the code that you provided for it to be easier to understand and added comments to it. Though, this way it is much less effective cause you calculate sum for left and right subtree of every node(on each call to calculateTilt), but it is still accepted by leetcode:
public class Solution {
int result = 0; //instance variable to accumulate result(tilt) for all nodes in the tree
public int findTilt(TreeNode root) {
calculateTilt(root);
return result;
}
private void calculateTilt(TreeNode root) {
if (root == null)
return;
int left = findTreeSum(root.left); //find sum of all nodes values of the left subtree
int right = findTreeSum(root.right); //find sum of all nodes values of the right subtree
result += Math.abs(left - right); //add tilt of current node to the result
calculateTilt(root.left); //recursively calculate tilt for the left subtree
calculateTilt(root.right); //recursively calculate tilt for the right subtree
}
//method to find sum of all nodes values for the tree starting at root
private int findTreeSum(TreeNode root){
if (root == null)
return 0;
return findTreeSum(root.left) + findTreeSum(root.right) + root.val;
}
}
Hope this will help!
Related
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;
}
}
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.
I have problems writing this method public int getHeight, where i have to find the height of the binary search tree, using recursion. The reason is that my main class, is made with private comparable mKey and private vertex mLeft, mRight, and mParent, instead of nodes. Would love some help.
public int getHeight(Tree t, int depth)
{
if(t == null){
return depth;
}
else{
return Math.max(getHeight(t.mLeft, depth + 1), getHeight(t.mRight, depth + 1))
}
}
This returns the length of the deepest branch in the tree.
EDIT:
call with getHeight(tree,0)
Im having trouble with a method that finds the height of the closest leaf. What i have just counts all of the leafs. would i have to separate the recursive calls into two conditional statements to check each one independently? any help or suggestions would be appreciated
this is my method
//find the distance to the closest leaf
public int closeLeaf()
{
int distance;
return distance = closeLeaf(root);
}
private int closeLeaf(StringNode n)
{
int dist = 0;
if(n == null)
{
dist = 0;//empty tree
}
else if(n.getLeft()== null && n.getRight()== null)
{
dist++;
}
else
{
dist =closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
}
return dist;
}
Returning values
Please don't do this:
int distance;
return distance = closeLeaf(root);
Just:
return closeLeaf(root);
On to the real question
Here you're adding up the distance to each leaf:
dist = closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
You probably just want to get the minimum of the two values (to tell you the distance to the closest one).
Instead of
dist =closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
which increments dist for every node encountered, use a static/class member variable that gets incremented each time the closeLeaf function is called.
Limit the recursion to finding a leaf, and the value of dist when you find one will give you the height of the closest leaf.
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);
}