finding the width of a binary tree - java

Finding the width of binary tree.
In my code for each leave i create a entry in a hash map and keep updating it when i found a node at leave i.Finally i will iterate the hashmap to find max width.But how can i do it without using any classleel/global varaiables?
Map<Integer,Integer> mp = new HashMap<Integer,Integer>();
void width(Node node,int level){
if(node==null)
return;
if(mp.containsKey(level)){
int count = mp.get(level);
mp.put(level, count+1);
}else{
mp.put(level, 1);
}
width(node.left, level+1);
width(node.right, level+1);
}

Just create the HashMap inside the method, then move all the work into an auxillary method, like this:
void width(Node node,int level){
Map<Integer,Integer> mp = new HashMap<Integer,Integer>();
widthImpl(mp, node, level);
// find maximum
}
private void widthImpl(Map<Integer,Integer> mp, Node node, int level) {
if(node==null)
return;
if(mp.containsKey(level)){
int count = mp.get(level);
mp.put(level, count+1);
}else{
mp.put(level, 1);
}
widthImpl(mp, node.left, level+1);
widthImpl(mp, node.right, level+1);
}

You don't need to keep track of the number of nodes per level.
Define the horizontal position of each node as the number of right children minus the number of left children that were traversed from the root to the node. The width will then be the maximum horizontal position minus the minimum horizontal position. The min/max positions could be passed around a recursive traversal in an array of two components.
Here's a code example of what I mean:
int getWidth(Node node) {
// current[0] is the number of left children traversed of the current path
// current[1] is the number of right children traversed of the current path
int[] current = { 0, 0 };
// extremes[0] is the minimum horizontal position
// extremes[1] is the maximum horizontal position
int[] extremes = { 0, 0 };
computeExtremes(node, current, extremes);
return (extremes[1] - extremes[0]);
}
void computeExtremes(Node node, int[] current, int[] extremes) {
if (node == null) { return; }
int position = current[1] - current[0];
if (extremes[0] > position) {
extremes[0] = position;
}
if (extremes[1] < position) {
extremes[1] = position;
}
current[0]++;
computeExtremes(node.left, current, extremes);
current[0]--;
current[1]++;
computeExtremes(node.right, current, extremes);
current[1]--;
}

If I understand it correctly you want to do something like this?
public Map<Integer,Integer> width( Node node ) {
Map<Integer,Integer> mp = new HashMap<Integer,Integer>();
width( node, 1, mp );
return mp;
}
private void width( Node node, int level, Map<Integer,Integer> mp ) {
if(node==null)
return;
if(mp.containsKey(level)){
int count = mp.get(level);
mp.put(level, count+1);
}else{
mp.put(level, 1);
}
width(node.left, level+1);
width(node.right, level+1);
}

This uses #nathan's algo, but passes by value.
Pair<int, int> extremes(Node node, int x, int y) {
if (node == null) return makePair(x,y);
Pair p1 = extremes(node.left, x-1, y);
Pair p2 = extremes(node.right, x, y+1);
return makePair(min(p1.x, p2.x), max(p1.y, p2.y))
}

See https://www.geeksforgeeks.org/maximum-width-of-a-binary-tree/
Use recursive with hash table
int getWidth(struct node* root, int level)
{
if(root == NULL)
return 0;
if(level == 1)
return 1;
else if (level > 1)
return getWidth(root->left, level-1) +
getWidth(root->right, level-1);
}
Use queue to dequeue parent and replace with children nodes
static int maxwidth(node root)
{
// Base case
if (root == null)
return 0;
// Initialize result
int maxwidth = 0;
// Do Level order traversal keeping
// track of number of nodes at every level
Queue<node> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty())
{
// Get the size of queue when the level order
// traversal for one level finishes
int count = q.size();
// Update the maximum node count value
maxwidth = Math.max(maxwidth, count);
// Iterate for all the nodes in
// the queue currently
while (count-- > 0)
{
// Dequeue an node from queue
node temp = q.remove();
// Enqueue left and right children
// of dequeued node
if (temp.left != null)
{
q.add(temp.left);
}
if (temp.right != null)
{
q.add(temp.right);
}
}
}
return maxwidth;
}

Something a little different:
int[] width(Node node){
if(node==null) {
return new int[]{};
}
int[] la = width(node.left);
int[] ra = width(node.right);
return merge(1, la, ra);
}
private int[] merge(int n0, int[] la, int[] ra) {
int maxLen = Math.max(la.length, ra.length);
int[] result = new int[maxLen+1];
result[0] = n0;
for (int i = 0; i < maxLen; ++i) {
result[i+1] = i >= la.length
? ra[i] : i >= ra.length
? la[i] : la[i] + ra[i];
}
return result;
}

Related

Inserting array to BST in-order traverse

I want to traverse over a given tree using in-order traversal. inserting the sorted array into the BST (keeping it the same shape)
This is my go:
public static BinTreeNode<Integer> ARR_TO_BST(BinTreeNode<Integer> root, int[] arr, int ind){
if (root.GetLeft() != null)
ARR_TO_BST(root.GetLeft(), arr, ind);
root.SetInfo(arr[ind]);
ind+=1;
if (root.GetRight() != null)
ARR_TO_BST(root.GetRight(), arr, ind);
return root;
The problem is that if the array is arr = {10,20,30,40,50,60}
and the tree is:
The return output is a tree that if I do an in-order traversal over it is: 10 20 10 20 10 20 ... and not 10 20 30 40 50 60
I need the output to be the same shape of the picture but with the values of arr the algorithm is to traverse -in order on the tree : left subtree - vertex - right subtree
but instead of reading the values we insert the values from arr to root
I would appreciate help! thank you
You never change ind. After the first call to ARR_TO_BST, it remains what it was before the call. Make ARR_TO_BST return the number of elements it placed:
if (root.GetLeft() != null)
ind = ARR_TO_BST(root.GetLeft(), arr, ind);
root.SetInfo(arr[ind]);
if (root.GetLeft() != null)
ind = ARR_TO_BST(root.GetLeft(), arr, ind + 1);
return ind;
and you should be all right.
You can use accomplish by keep tracking the index of each element to add it back to the result array
static class BST {
private class Node {
private Integer key;
private Node left, right;
private int index;
public Node(Integer key, int index) {
this.key = key;
this.index = index;
}
}
private Node root;
private int size = 0;
public void put(int[] arr) {
if (size >= arr.length)
return;
root = put(root, arr[size], size);
size++;
put(arr);
}
private Node put(Node node, int key, int index) {
if (node == null)
return new Node(key, index);
int cmp = Integer.valueOf(key).compareTo(node.key);
if (cmp < 0)
node.left = put(node.left, key, index);
else if (cmp > 0)
node.right = put(node.right, key, index);
else
node.key = key;
return node;
}
public int size() {
return size;
}
public int[] keys() {
int[] result = new int[size];
get(root, result, 0);
return result;
}
public void get(Node node, int[] result, int i) {
if (i >= result.length || node == null)
return;
result[node.index] = node.key;
get(node.left, result, ++i);
get(node.right, result, ++i);
}
}
, main
public static void main(String[] args) {
BST bst = new BST();
bst.put(new int[] { 10, 20, 5, 40, 1, 60, -10, 0 });
for (int num : bst.keys()) {
System.out.print(num + " ");
}
}
, output
10 20 5 40 1 60

number of paths in a binary tree with a given sum

I am solving the problem https://leetcode.com/problems/path-sum-iii/
I'll also briefly mention it here:
Find the number of paths in a Binary tree whose sum = sum. The path does not necessarily have to begin (end) at the root (leaf). As long as the path goes downward it should be considered as a valid path.
Here is my solution:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int pathSum(TreeNode root, int sum) {
int path = 0;
if(root.val == sum)
return 1;
else if(root.left == null && root.right == null)
return 0;
if(root.left != null){
path += pathSum(root.left, sum - root.val);
path += pathSum(root.left, sum);
}
if(root.right != null){
path += pathSum(root.right, sum - root.val);
path += pathSum(root.right, sum);
}
return path;
}
}
The answer as per their system is 3, but I am getting the answer as 4 for the following input:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
I have spent hours trying to reason why my code wold not work, but I cannot figure out the problem.
Sorry for a naive question :( But this is killing me!
I'm not sure what's wrong in your solution, but I don't think it's correct. For one thing, if your root was 8 you would immediately return and count only the root as solution. This is how I would do it:
import java.util.ArrayList;
public class Solution {
public static int pathSum(TreeNode root, int sum) {
return pathSum(root, sum, 0, new ArrayList<Integer>());
}
public static int pathSum(TreeNode root, int sum, int count, ArrayList<Integer> arr) {
arr.add(root.val);
int acc = 0;
for (int i=arr.size()-1; i>=0; i--) {
acc += arr.get(i);
if (acc == sum)
count++;
}
if(root.left != null)
count = pathSum(root.left, sum, count, arr);
if(root.right != null)
count = pathSum(root.right, sum, count, arr);
arr.remove(arr.size()-1);
return count;
}
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int v) {
this.val = v;
}
}
public static void main(String[] args) {
TreeNode root = new TreeNode(10);
root.left = new TreeNode(5);
root.right = new TreeNode(-3);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(2);
root.right.right = new TreeNode(11);
root.left.left.left = new TreeNode(3);
root.left.left.right = new TreeNode(-2);
root.left.right.right = new TreeNode(1);
System.out.println(pathSum(root, 8));
}
}
The idea is to populate an aarray with the value along the path as you traverse the tree recursively, making sure you remove elements as you return. When you visit a node, you have to consider all the sums from that node to any node on the path to the root. Any of them can add up to your reference value. This implementation is O(nlogn), as you traverse n nodes, and for each you traverse an array of len up to log(n).
your code cant satisfy this constraint:
these nodes should be continuous.
e.g the root(value 10) of this tree and the leaf(value -2) of this tree, the sum of them is equals 8. but it dont satisfy continous, so It cant count.
Unfortunately, your code cant filter this case.
an alternative Solution:
public class Solution {
public int pathSum(TreeNode root, int sum) {
int path = traverse(root,sum);
return path;
}
public int traverse(TreeNode root, int sum){
int path = 0;
if(root==null){
return 0;
}
else{
path += calcu(root,sum);
path += traverse(root.left,sum);
path += traverse(root.right,sum);
return path;
}
}
private int calcu(TreeNode root, int sum) {
if(root==null){
return 0;
}
else if(root.val==sum){
return 1 + calcu(root.left,sum-root.val)+calcu(root.right,sum-root.val);
}
else{
return calcu(root.left,sum-root.val)+calcu(root.right,sum-root.val);
}
}
}
explanation: traverse this tree and make every treeNode as root node, find target path under the premise continous.
the problem with your solution is that you do not start from an initial sum, if you are in a new inner path.
so you should keep track of both the accomulated sum and the original sum as well when you move inner path.
find below a modified copy of your algorithm.
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
boolean visitedAsRoot = false;
TreeNode(int x) {
val = x;
}
}
public static int pathSum(TreeNode root, int accomulate, int sum) {
int path = 0;
if (root.val == accomulate)
return 1;
else if (root.left == null && root.right == null)
return 0;
if (root.left != null) {
path += pathSum(root.left, accomulate - root.val, sum);
if (!root.left.visitedAsRoot) {
root.left.visitedAsRoot = true;
path += pathSum(root.left, sum, sum);
}
}
if (root.right != null) {
path += pathSum(root.right, accomulate - root.val, sum);
if (!root.right.visitedAsRoot) {
root.right.visitedAsRoot = true;
path += pathSum(root.right, sum, sum);
}
}
return path;
}
public static void main(String args[]) {
TreeNode t1 = new TreeNode(3);
TreeNode t2 = new TreeNode(-2);
TreeNode t3 = new TreeNode(1);
TreeNode t4 = new TreeNode(3);
TreeNode t5 = new TreeNode(2);
TreeNode t6 = new TreeNode(11);
TreeNode t7 = new TreeNode(5);
TreeNode t8 = new TreeNode(-3);
TreeNode t9 = new TreeNode(10);
t4.left = t1;
t4.right = t2;
t5.right = t3;
t7.left = t4;
t7.right = t5;
t8.right = t6;
t9.left = t7;
t9.right = t8;
System.out.println(pathSum(t9, 8, 8));
}
The problem with your solution is that it is also counting 10 - 2 = 8. where 10 is the topmost root node and -2 is a bottom leaf. It ignores all the path in between.
I managed to solve it with a tamperedSum boolean.
public static int pathSum(TreeNode root, int sum, boolean tamperedSum)
{
int path = 0;
if(root.val == sum)
path = 1;
if(root.left == null && root.right == null)
return path;
if(root.left != null){
path += pathSum(root.left, sum - root.val, true);
if (!tamperedSum)
path += pathSum(root.left, sum, false);
}
if(root.right != null){
path += pathSum(root.right, sum - root.val, true);
if (!tamperedSum)
path += pathSum(root.right, sum, false);
}
return path;
}
The tamperedSum boolean is set to true when we have deducted values (of nodes) from the original sum which in this case is 8.
We would invoke it as:
pathSum(root, sum, false)
The idea is that if the sum has been tampered i.e a node value on the path has already been deducted, we are no longer allowed to pass it as-is to the branch below the node.
So, we set tamperedSum to true whenever we deduct the node value from the sum as: sum - root.value. After that, all nodes below it are not allowed to pass through the sum without deducting their node value from it.

Binary Tree Level Sum -

A basic Java sample: Given a binary tree and an integer which is the depth of the target level.
And calculate the sum of the nodes in the target level.
I am adding the value in the functions to the left and right node. Why this solution doesn't work in this case, Can anyone help explain?
Also, when the travese function got returned, is it returning to the parent root or more like break; in for loop and the flow got stopped?
private int sum;
public int levelSum(TreeNode root, int level) {
sum = 0;
traverse(root, 1, level, 0);
return sum;
}
public void traverse(TreeNode root, int depth, int level, int sum) {
if(root == null) {
return;
}
if(depth == level) {
return;
}
if(root.left != null) {
traverse(root.left, depth + 1, level, sum + root.left.val);
}
if(root.right != null) {
traverse(root.right, depth + 1, level, sum + root.right.val);
}
}
First of all, you didn't return the result of summation. You will have to return it.
Then, since you wrote "in the target level", I guess you will have to sum up nodes only in the target level, not nodes before the level.
Try this:
public int levelSum(TreeNode root, int level) {
return traverse(root, 1, level);
}
public void traverse(TreeNode root, int depth, int level){
int sum = 0;
if(root == null || depth > level){
return 0;
}
if (depth == level) sum += root.val;
if(root.left != null) {
sum += traverse(root.left, depth + 1, level);
}
if(root.right != null) {
sum += traverse(root.right, depth + 1, level);
}
return sum;
}

Counting specific nodes in linked list Java

I have to count nodes in Circular Doubly Linked List in interval [-100;100]. I know how to do that when i'm implementing a node. Here's code :
public void insert(int val){
....
if((val >= -100) && (val <= 100)){
number++;
}
.....
But when i'm deleting a node at given position (pos), i have no idea how to check the value of that node, so i don't know if "number" stays the same or it decreases.
Here is code of deleting node:
public void deleteAtPos(int pos){
if (pos == 1){
if(size == 1){
start = null;
end = null;
size = 0;
number = 0;
return;
}
start = start.getLinkNext();
start.setLinkPrev(end);
end.setLinkNext(start);
size--;
return;
}
if (pos == size){
end = end.getLinkPrev();
end.setLinkNext(start);
start.setLinkPrev(end);
size--;
}
}
Node ptr = start.getLinkNext();
for (int i = 2; i <= size; i++){
if (i == pos){
Node p = ptr.getLinkPrev();
Node n = ptr.getLinkNext();
p.setLinkNext(n);
n.setLinkPrev(p);
size--;
return;
}
ptr = ptr.getLinkNext();
}
}
From what i understand , you can simply check the value of the node by adding
ptr.getval() or start.getval() //depending on the value of pos(aasuming getval is your function to retrieve node data)

Counting left-child nodes in a Tree

I am supposed to implement a recursive method that counts the amount of left-child tree nodes. My code so far is:
private int countLeftNodes(IntTreeNode node){
int c = 0;
if (node != null){
c = 1 + countLeftNodes(node.left);
countLeftNodes(node.right);
}
return c;
}
It returns a number much smaller than what it should be. I have a feeling that my traversal is off because it seems to only count the very left child nodes, and then terminates. When I call this method on an IntTree of size 16 I should get 8 left-child nodes, 7 right-child nodes, and one root, but instead I get 4 left-child nodes.
You never count the left nodes in the right tree.
private int countLeftNodes(IntTreeNode node)
{
int c = 0;
if (node.left != null)
{
c += 1 + countLeftNodes(node.left);
}
if(node.right != null)
{
c += countLeftNodes(node.right);
}
return c;
}
To count left-child nodes you can do:
private int countLeftNodes(IntTreeNode node) {
// no tree no left-child nodes
if(node == null) {
return 0;
}
// left-child count of current node.
int c = 0;
// does the current node have a left-child ?
if (node.left != null){
c = 1;
}
// return left-child count of current node +
// left-child count of left and right subtrees
return c + countLeftNodes(node.left) + countLeftNodes(node.right);
}
private int countLeftNodes(IntTreeNode node){
int c = 0;
if (node != null){
if(node.left!=null) {
c = 1 + countLeftNodes(node.left);
}
if(node.right!=null){
c +=countLeftNodes(node.right);
}
}
return c;
}
easiest place to check that is in the parent.
private int countLeftNodes(IntTreeNode node){
int c = 0;
if(node.left != null)
{
c++;
c+= countLeftNodes(node.left)
}
if(node.right != null)
{
c+= countLeftNodes(node.right);
}
return c;
}
My favorite style when using recursion is to use a wrapper function of some sort where the main method calls another that does the grunt work:
private int countLeftNodes(IntTreeNode node){
int totalCount = reallyCountLeftNodes(IntTreeNode node, 0);
return totalCount;
}
private int reallyCountLeftNodes(IntTreeNode n, Int sum){
if (n.left == NULL && n.right == NULL){ //check if we've hit rock bottom
return sum;
} else if (n.left == NULL) { //if the node's left is nil, go right
reallyCountLeftNodes(n.right, sum++);
} else {
reallyCountLeftNodes(n.left, sum++); // Going as far left as possible!
}
}
Notice how the main function calls another. I find this style to be cleaner and easier to understand. Also, the second function has a count variable for you to use.

Categories

Resources