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;
}
Related
What I'm trying to do right now is find the minimum value of repeat count in my binary search tree (BST).
What this means is that the BST is normal when inserting values, but then when it gets the same value twice it instead will increment the value of repeat count, which the tree isn't dependent on (so I can't just go left for the minimum value).
I have tried getting the minimum value but it always comes up short. The function trying to get the smallest is findSmallest
public static void main(String[] args) {
int x = 0; //random number
Random rnum = new Random();
SBT sbt = new SBT();
for(int i = 0; i < 100; i++){
x = rnum.nextInt(20) + 1;
sbt.insert(x);
}
sbt.printLargestCount();
sbt.printSmallestCount();
sbt.FS();
sbt.deleteBoth();
System.out.println("Sum of the key values is: " + sbt.sumKeyValue());
System.out.println("Sum of the repeat counts is: " + sbt.sumReapeatCount());
sbt.inorder();
}
Here is the function trying to get the value I am right now trying to go through all the node in the tree and comparing them to the current smallest value.
If the nodes repeatCount is smaller that value it will change value and a global node smallestCount.
I have added those globals below.
private BSTNode root;
private BSTNode largestCount;
private BSTNode smallestCount;
private int sumKeyVal;
public void FS(){
findSmallest(root, 0);
System.out.println("data is: " + smallestCount.data + " repeatCount is: " + smallestCount.repeatCount);
}
private void findSmallest(BSTNode r, int val){
if(r == null) return;
if(r == root)val = r.repeatCount;
if(r.repeatCount < val){
val = r.repeatCount;
smallestCount = r;
System.out.println(val);
}
if(r.right == null && r.left == null)
return;
else if(r.left != null)
findSmallest(r.left,val);
else if(r.right != null)
findSmallest(r.right,val);
}
private BSTNode insert(int x, BSTNode t){
if (t == null){
t = new BSTNode(x);
smallestCount = t;
}
else if (x < t.data)
t.left = insert( x, t.left );
else if (x > t.data)
t.right = insert( x, t.right );
else
t.height = max( height( t.left ), height( t.right ) ) + 1;
return t;
}
private int height(BSTNode t ) {
return t == null ? -1 : t.height;
}
// Function to max of left/right node
private int max(int lhs, int rhs) {
return lhs > rhs ? lhs : rhs;
}
Here is the node class used:
public class BSTNode {
BSTNode left, right;
int data;
int height;
int repeatCount;
/* Constructor */
public BSTNode(){
left = null;
right = null;
data = 0;
height = 0;
repeatCount = 0;
}
/* Constructor */
public BSTNode(int n){
left = null;
right = null;
data = n;
height = 0;
repeatCount = 0;
}
}
I figured it out and tested the code seems to work. Below is the block of code changed.
public void FS(){
findSmallest(root, 0);
}
private int findSmallest(BSTNode r, int val){
if(r == null) return val;
if(r == root)val = r.repeatCount;
if(r.repeatCount < val){
val = r.repeatCount;
smallestCount = r;
}
val = findSmallest(r.left,val);
val = findSmallest(r.right,val);
return val;
}
Getting rid of the if else statements and going with a check for null at the begging traversed through the tree and kept the smallest along the way.
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.
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;
}
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)
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.