Search code examples
javaalgorithmrecursionbinary-treebacktracking

When backtracking is necessary?


For example the following two questions about DFS a binary tree, why the first one need back tracking(delete the last element in the working set every time whenever hit a leaf node), and the other one do not? They both asked for all the paths meet the requirement, not trying to find whether a path exist or not, since the path is already reached to an end when hit a leaf, in order to format other possible path shouldn't we back track to the last node we visit?

https://leetcode.com/problems/path-sum-ii/

https://leetcode.com/problems/binary-tree-paths/

Answer for first question:

 public List<List<Integer>> pathSum(TreeNode root, int sum) {
     List<List<Integer>> finalResult=new ArrayList<List<Integer>>();
     List<Integer> tempResult = new ArrayList<Integer>();
     pathSumHelper(root,sum,tempResult,finalResult);
     return finalResult;
 }
 public void pathSumHelper(TreeNode node, int sum, List <Integer> tempResult, List<List<Integer>> finalResult){
     if(node == null) return;
     sum -= node.val;
     if( node.left == null && node.right == null ){  
        if( sum == 0){
          tempResult.add(node.val);
          finalResult.add(new ArrayList<Integer>(tempResult));
          tempResult.remove(tempResult.size() -1);
        }
     return;
     }
     tempResult.add(node.val);
     pathSumHelper(node.left, sum, tempResult, finalResult);
     pathSumHelper(node.right, sum, tempResult, finalResult);
     tempResult.remove(tempResult.size() -1 );
 }

Answer for the second question:

 public List<String> binaryTreePaths(TreeNode root) {
    List<String> finalResult = new ArrayList<String>();
    String tempResult = "";
    findPath(root, tempResult, finalResult);
    return finalResult;
 }

 public void findPath(TreeNode node, String tempResult, List<String> finalResult){
    if( node == null ){
        return;
    }
    if(node.left == null && node.right == null){
        tempResult += String.valueOf(node.val);        
        finalResult.add(tempResult);
        // why no delete last integer added in tempResult before return?
        return;
    }
    tempResult += String.valueOf(node.val);
    findPath(node.left, tempResult+"->", finalResult);
    findPath(node.right, tempResult+"->", finalResult);
    // same, why no delete last integer added in tempResult before return?               
 }

Solution

  • In the second algorithm, when you make a recursive call to findPath, you are using + operator, while passing tempResult + "->" as an argument. + operator causes a concatenation which creates a new String object. Basically at each level of recursion, you pass along a fresh String object to the lower levels, and leave tempResult variable of each level out of the reach of lower levels.

    Consequently, you actually do not have access to the String object of the upper levels of recursion and even if you backtracked, it would only update the String object passed to that level of recursion and not the tempResult belonging to an upper level, which was never chanced to begin with! That's why backtracking is not necessary in the second solution, and is therefore not done.