0

I am solving a coding question where we need to remove all the sub-trees of a binary tree that only has 0 as its value . Question link https://leetcode.com/problems/binary-tree-pruning/ The solution that worked for me is this

public TreeNode pruneTree(TreeNode root) {
    if (root == null)
        return null;
    root.left = pruneTree(root.left);
    root.right = pruneTree(root.right);
    if (root.val == 0 && root.left == null && root.right == null)
        root = null;
    else
        return root;
   // pruneTree1(root);
 //   printTree(root);
    return root;
}

The solution I tried submitting earlier was this

public TreeNode pruneTree(TreeNode root) {
    pruneTree1(root);
    return root;
}

TreeNode pruneTree1 (TreeNode root) {
    if(root ==null)
        return root ;
    root.left = pruneTree1(root.left);
    root.right = pruneTree1(root.right);
    if(root.left==null && root.right==null && root.val==0) {
        System.out.println(root.val);
        root =null;
    }
    return root;
}

My question/doubt is why the second solution wasn't changing the original tree. My understanding was Java is pass by value but when we pass an Object by its variable name its a reference to original object and we can change its content.

Why was it not working in this case. Is it because I am trying to set the whole object as null and not just its value ?

I tired recreating the scenario with another example and the code behaves differently in this case . Here's what i tried

public void run1() {
        TreeNode root = new TreeNode();
        root.val = 2;
        TreeNode left = new TreeNode();
        left.val = 3;
        TreeNode right = new TreeNode();
        right.val = 4;
        TreeNode leftLeft = new TreeNode();
        leftLeft.val = 5;
        TreeNode rightRight = new TreeNode();
        rightRight.val = 6;
        root.left = left;
        root.right = right;
        left.left = leftLeft;
        right.right = rightRight;
        System.out.println(root.left.left.val);
        TreeNode root2 = makeNull(root);
        System.out.println(root.left.left);
        System.out.println(root2.left.left);

    };

 public   TreeNode  makeNull (TreeNode root){
        if(root ==null)
            return root ;
        root.left = makeNull(root.left);
        root.right = makeNull(root.right);
        if(root.val==5)
            root=null;
        //  left.left = null;
        return root;
    }

In the example i both root.left.left and root2.left.left is set as null when i print it . Why it acts like parameter is passed as reference in this case but not in the above example.

Aman Kumar Sinha
  • 407
  • 6
  • 17
  • 2
    1) Java is always pass by value. 2) If the parameter is an object, the object's reference is passed by value. This means that the called function can *modify* the object's value, and the modification will be seen by the caller. 3) It also means that any changes to the reference (e.g. setting "root = null") will *NOT* be seen by the caller. 4) Regarding Solution 1 vs. Solution 2: Q: Did you step through the code in the debugger? What did you find? – paulsm4 Sep 06 '22 at 05:31
  • Note: do yourself a favor and use consistent formatting (including indentation). It will make things easier for you, and for others trying to assist you. – Chris Sep 06 '22 at 05:43
  • Does this answer your question? [Is Java "pass-by-reference" or "pass-by-value"?](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) – tgdavies Sep 06 '22 at 05:44
  • @tgdavies I went through this answer before but wasn't able to figure out why in this specific case it isn't working as its supposed to . I am passing an object int the second solution so ideally it should change the original object as Object variable name is just a reference to actual object – Aman Kumar Sinha Sep 06 '22 at 05:50
  • @AmanKumarSinha - When I look into the requirements: you're never supposed to return null. It's required to *always* return the original tree. Reconsider your solution. In fact, it does not work. – Andreas Dolk Sep 06 '22 at 06:06
  • @AndreasDolk it got accepted by leetcode so not sure what you are referring to – Aman Kumar Sinha Sep 06 '22 at 06:08
  • @AmanKumarSinha - consider a tree [0]. You'd return null instead of the 'same' tree. It's a corner case. I'd expect, that you'd have to return the same tree, [0], because 'null' does not fulfill the 'same tree' requirement. On the other hand, we could argue, that the root was supposed to be removed. In that case, the tree model was broken, because i'd require some invisible root with a single child node, so that we could remove that and still return the tree model. – Andreas Dolk Sep 06 '22 at 06:19
  • 1
    @AndreasDolk Your answer makes sense to me but i guess either that case wasn't a test case for the question or the expectation was to remove a tree completely when it has only one node with value 0 . In any case I see your point . Thanks for pointing that out – Aman Kumar Sinha Sep 06 '22 at 06:21

1 Answers1

0

In the second example you nowhere worked with the result of pruneTree1(). But the parameter of that method never got modified for its caller (due to pass-by-value).

Update for your added example:

root.left and root2.left are referring to the same object. As root.left.val != 5 you also don't change that.

You assign root.left and root.right to the return value of the method, but return the input parameter in the most cases. So as long as you don't return null, the same objects are still referenced.

cyberbrain
  • 3,433
  • 1
  • 12
  • 22
  • You are right and thats where my confusion is . The solution works when i return (use the ) the return object from pruneTree1 . But Why do i need to use the returned object . Why the prune1 function doesn't change the original tree itself when its parameter ( Object variable name ) is a reference to original Object. @cyberbrain – Aman Kumar Sinha Sep 06 '22 at 05:54
  • 1
    you nowhere change the original tree, this would mean that you modify the value of `root.val` or `root.left` or `root.right`. You only modify the reference to the tree element (`root`) with `root = null;` That change is not seen by the caller as change of the parameter (because `root` is the reference to the object, that is passed by value and therefore never changes for the caller), but only as return value. You can think of it as if the caller has the behaviour that all parameters of methods are `final` - this is different for the callee. – cyberbrain Sep 06 '22 at 05:58