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.
Related
I want to delete the leaf nodes, the values of which are outside a given range (say [L R]). I made a solution in which I was simply traversing all the nodes and checking if my current leaf node's value is in the given range or not. If it is not then I'm removing this node.
My approach -
private static Node trim(Node root, int L, int R) {
if (root == null)
return null;
if (root.left == null && root.right == null) {
if (root.val < L || root.val > R)
return null;
else
return root;
}
root.left = trim(root.left, L, R);
root.right = trim(root.right, L, R);
return root;
}
But this runs in o(n) since I'm traversing all the nodes (and I'm not using BST's property anywhere). Can anyone help me in finding a better/ optimized solution ?
Like m.raynal said, since you only want to remove leafs you can't get better than O(n).
You only can add a shortcut when all the nodes in the branch will be inside the range, something like
private static Node trim(Node root, int L, int R) {
return trim(root, L, R, null,null);
}
private static Node trim(Node root, int L, int R, Integer lBound, Integer rBound)
{
if (root == null)
return null;
if (lBound != null && lBound >= L && rBound != null && rBound <= R ) {
return root;
}
if (root.left == null && root.right == null) {
if (root.val < L || root.val > R)
return null;
else
return root;
}
root.left = trim(root.left, L, R, lBound , root.val);
root.right = trim(root.right, L, R, root.val, rBound );
return root;
}
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.
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)
the problem is: calculate the total sum of all root-to-leaf numbers. for example: if the tree is (1,2,3), 1 is root, 2 is left child, 3 is right child, two paths: 1->2 1->3, sum=12+13=25
this is my correct recursive solution. in the helper method, return the sum:
public int sumNumbers(TreeNode root) {
if (root == null) {
return 0;
}
return getSum(root, 0);
}
private int getSum(TreeNode root, int value) {
if (root.left == null && root.right == null) {
return root.val + value * 10;
}
int sum = 0;
if (root.left != null) {
sum += getSum(root.left, value * 10 + root.val);
}
if (root.right != null) {
sum += getSum(root.right, value * 10 + root.val);
}
return sum;
}
but when I add the sum as a parameter in the helper method, I always got 0.
public int getSum(TreeNode root) {
int sum = 0, path = 0;
helper(root, path, sum);
return sum;
}
private void helper(TreeNode root, int path, int sum) {
if (root == null) {
return;
}
int path = 10 * path + root.val;
if (root.left == null && root.right == null) {
sum += path;
return;
}
helper(root.left, path, sum);
helper(root.right, path, sum);
}
I believe there must be some points I misunderstand about the recursion. thank you in advance to give me some explanation why the value of sum is not 'transferred' back to the sum in getSum method.
Also you need to think about overflow. My solution has passed in LeetCode, hopefully it gives you some tips.
public class Solution {
private long sum = 0;
public int sumNumbers(TreeNode root) {
if(root == null) return 0;
sum(root, new Stack<Integer>());
if(this.sum >= Integer.MAX_VALUE){
return Integer.MAX_VALUE;
}
return (int)this.sum;
}
private void sum(TreeNode node, Stack<Integer> stack){
if(node == null) return;
stack.push(node.val);
if(node.left == null && node.right == null){
long tempSum = 0;
int index = 0;
for(int i=stack.size()-1;i>=0;i--){
int k = stack.get(i);
int times = (int)Math.pow(10, index++);
k *= times;
tempSum += k;
}
this.sum += tempSum;
}
sum(node.left, stack);
sum(node.right, stack);
if(stack.size() > 0)
stack.pop();
}
}
ZouZou is right about the pass by value, although this only applies to primitives. Changing your sum to an Integer instead of int should do the trick, other solution would be to us a global variable (i.e. field)
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;
}