java binary search tree find closest leaf - java

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.

Related

Binary Tree basics

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!

Finding the Height of a Binary Search Tree in Java using Vertex

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)

find longest path of white nodes

This question was asked in an interview:
Tree with black and white nodes is given. Find a longest path of white nodes in the given tree.Is the approach below correct or somebody help with a better approach thanks!
int Longest(node root, int max)
{
if(root==null || root.color == black)
return 0;
if(root.color == white)
{
int curmax =1+ firstlongest(root.child) + secondlongest(root.child);
if(curmax>max)
max = curmax;
return curmax;
}
if(root.color == black)
{
for(all children)
{
int curmax =1+ firstlongest(root.child) + secondlongest(root.child);
}
if(curmax>max)
max =curmax;
return 0;
}
}
int firstlongest(node* child){//will calculate first longest of children and similarly
secondlongest gives second.Finally max will have length of longest path.
Intro:
First remember how to find a longest path in a tree. You take an arbitrary vertex v, find the farthest from it vertex u with bfs, then find the farthest from u vertex t, again with bfs, and (u,t) path will be the longest in the tree. I will not prove it here, you can either google for it or try to prove yourself (it's quite obvious though, if you run it on some examples).
Solution:
Now your problem. We don't need black nodes, so let's throw them away :) The remaining graph will be a forest, i.e. set of trees. Find longest paths for every tree with known algorithm and choose the longest among all.
Complexity:
Described algo will perform one linear pass to remove black nodes, and two linear bfs for each tree in the forest, which are linear to all nodes in graph. Totally: O(n) + O(n+m) + O(n+m) = O(n+m)
Your procedure only seems to compute paths that go down. Assuming all nodes white, it will miss the longest path in this tree:
r
/
a
/ \
b c
/ \
d e
The longest path is dbace.
The code seems incorrect for me. The following section:
if(root.color == black)
{
for(all children)
{
int curmax = max(longest(root.child[i], max));
}
if(curmax>max)
max =curmax;
return 0;
}
will never be executed, because if root.color == black method will return 0 earlier.
Here is how I would do this:
private static int longestWhitePathFromRootLength (Node node)
{
if (node.color == BLACK)
return 0;
else // node.color == WHITE
{
int l = 0;
for (Node n: node.children)
{
l = Math.max (l, longestWhitePathFromRootLength (n));
}
return l + 1;
}
}
public static int longestWhitePathLength (Node node)
{
int l = 0;
for (Node n: node.children)
{
l = Math.max (l, longestWhitePathLength (n));
}
return Math.max (l, longestWhitePathFromRootLength (node));
}

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

Solve n-puzzle in Java

I'm trying to implement a program to solve the n-puzzle problem.
I have written a simple implementation in Java that has a state of the problem characterized by a matrix representing the tiles. I am also able to auto-generate the graph of all the states giving the starting state. On the graph, then, I can do a BFS to find the path to the goal state.
But the problem is that I run out of memory and I cannot even create the whole graph.
I tried with a 2x2 tiles and it works. Also with some 3x3 (it depends on the starting state and how many nodes are in the graph). But in general this way is not suitable.
So I tried generating the nodes at runtime, while searching. It works, but it is slow (sometimes after some minutes it still have not ended and I terminate the program).
Btw: I give as starting state only solvable configurations and I don't create duplicated states.
So, I cannot create the graph. This leads to my main problem: I have to implement the A* algorithm and I need the path cost (i.e. for each node the distance from the starting state), but I think I cannot calculate it at runtime. I need the whole graph, right? Because A* does not follow a BFS exploration of the graph, so I don't know how to estimate the distance for each node. Hence, I don't know how to perform an A* search.
Any suggestion?
EDIT
State:
private int[][] tiles;
private int pathDistance;
private int misplacedTiles;
private State parent;
public State(int[][] tiles) {
this.tiles = tiles;
pathDistance = 0;
misplacedTiles = estimateHammingDistance();
parent = null;
}
public ArrayList<State> findNext() {
ArrayList<State> next = new ArrayList<State>();
int[] coordZero = findCoordinates(0);
int[][] copy;
if(coordZero[1] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] + 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[1] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] - 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0] + 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0] - 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
return next;
}
private State checkNewState(int[][] tiles) {
State newState = new State(tiles);
for(State s : Solver.states)
if(s.equals(newState))
return null;
return newState;
}
#Override
public boolean equals(Object obj) {
if(this == null || obj == null)
return false;
if (obj.getClass().equals(this.getClass())) {
for(int r = 0; r < tiles.length; r++) {
for(int c = 0; c < tiles[r].length; c++) {
if (((State)obj).getTiles()[r][c] != tiles[r][c])
return false;
}
}
return true;
}
return false;
}
Solver:
public static final HashSet<State> states = new HashSet<State>();
public static void main(String[] args) {
solve(new State(selectStartingBoard()));
}
public static State solve(State initialState) {
TreeSet<State> queue = new TreeSet<State>(new Comparator1());
queue.add(initialState);
states.add(initialState);
while(!queue.isEmpty()) {
State current = queue.pollFirst();
for(State s : current.findNext()) {
if(s.goalCheck()) {
s.setParent(current);
return s;
}
if(!states.contains(s)) {
s.setPathDistance(current.getPathDistance() + 1);
s.setParent(current);
states.add(s);
queue.add(s);
}
}
}
return null;
}
Basically here is what I do:
- Solver's solve has a SortedSet. Elements (States) are sorted according to Comparator1, which calculates f(n) = g(n) + h(n), where g(n) is the path cost and h(n) is a heuristic (the number of misplaced tiles).
- I give the starting configuration and look for all the successors.
- If a successor has not been already visited (i.e. if it is not in the global set States) I add it to the queue and to States, setting the current state as its parent and parent's path + 1 as its path cost.
- Dequeue and repeat.
I think it should work because:
- I keep all the visited states so I'm not looping.
- Also, there won't be any useless edge because I immediately store current node's successors. E.g.: if from A I can go to B and C, and from B I could also go to C, there won't be the edge B->C (since path cost is 1 for each edge and A->B is cheaper than A->B->C).
- Each time I choose to expand the path with the minimum f(n), accordin to A*.
But it does not work. Or at least, after a few minutes it still can't find a solution (and I think is a lot of time in this case).
If I try to create a tree structure before executing A*, I run out of memory building it.
EDIT 2
Here are my heuristic functions:
private int estimateManhattanDistance() {
int counter = 0;
int[] expectedCoord = new int[2];
int[] realCoord = new int[2];
for(int value = 1; value < Solver.SIZE * Solver.SIZE; value++) {
realCoord = findCoordinates(value);
expectedCoord[0] = (value - 1) / Solver.SIZE;
expectedCoord[1] = (value - 1) % Solver.SIZE;
counter += Math.abs(expectedCoord[0] - realCoord[0]) + Math.abs(expectedCoord[1] - realCoord[1]);
}
return counter;
}
private int estimateMisplacedTiles() {
int counter = 0;
int expectedTileValue = 1;
for(int i = 0; i < Solver.SIZE; i++)
for(int j = 0; j < Solver.SIZE; j++) {
if(tiles[i][j] != expectedTileValue)
if(expectedTileValue != Solver.ZERO)
counter++;
expectedTileValue++;
}
return counter;
}
If I use a simple greedy algorithm they both work (using Manhattan distance is really quick (around 500 iterations to find a solution), while with number of misplaced tiles it takes around 10k iterations). If I use A* (evaluating also the path cost) it's really slow.
Comparators are like that:
public int compare(State o1, State o2) {
if(o1.getPathDistance() + o1.getManhattanDistance() >= o2.getPathDistance() + o2.getManhattanDistance())
return 1;
else
return -1;
}
EDIT 3
There was a little error. I fixed it and now A* works. Or at least, for the 3x3 if finds the optimal solution with only 700 iterations. For the 4x4 it's still too slow. I'll try with IDA*, but one question: how long could it take with A* to find the solution? Minutes? Hours? I left it for 10 minutes and it didn't end.
There is no need to generate all state space nodes for solving a problem using BFS, A* or any tree search, you just add states you can explore from current state to the fringe and that's why there is a successor function.
If BFS consumes much memory it is normal. But I don't know exactly fro what n it would make problem. Use DFS instead.
For A* you know how many moves you made to come to current state and you can estimate moves need to solve problem, simply by relaxing problem. As an example you can think that any two tiles can replace and then count moves needed to solve the problem. You heuristic just needs to be admissible ie. your estimate be less then actual moves needed to solve the problem.
add a path cost to your state class and every time you go from a parent state P to another state like C do this : c.cost = P.cost + 1 this will compute the path cost for every node automatically
this is also a very good and simple implementation in C# for 8-puzzle solver with A* take a look at it you will learn many things :
http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a

Categories

Resources