什么时候需要回溯?

时间:2016-03-23 16:38:45

标签: java algorithm recursion binary-tree backtracking

例如以下关于DFS的两个问题是二叉树,为什么第一个需要回溯跟踪(每次命中叶节点时都删除工作集中的最后一个元素),另一个不是?他们都要求所有的路径都满足要求,而不是试图找出路径是否存在,因为路径已经到达了一个叶子的末端,为了格式化其他可能的路径,我们不应该回溯到我们访问的最后一个节点?

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

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

回答第一个问题:

 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 );
 }

回答第二个问题:

 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?               
 }

1 个答案:

答案 0 :(得分:1)

在第二种算法中,当您对mysql> select * from t1 order by A DESC, C DESC, D ASC; +------+------+------+------------+ | A | B | C | D | +------+------+------+------------+ | 1 | 1 | 4 | 2016-01-04 | | 1 | 0 | 4 | 2016-01-07 | | 1 | 1 | 3 | 2016-01-03 | | 1 | 1 | 3 | 2016-01-06 | | 1 | 1 | 2 | 2016-01-02 | | 1 | 1 | 2 | 2016-01-05 | | 1 | 0 | 2 | 2016-01-09 | | 1 | 1 | 1 | 2016-01-01 | | 1 | 1 | 1 | 2016-01-04 | | 1 | 0 | 1 | 2016-01-08 | +------+------+------+------------+ 10 rows in set (0.00 sec) -- query wanted mysql> select t1.* -> from t1 CROSS JOIN (select @even := 0, @odd := 0) param -> order by -> A DESC, -> IF(B = 1, 2*(@odd := @odd + 1), 2*(@even := @even + 1) + 1), -> C DESC, -> D ASC; +------+------+------+------------+ | A | B | C | D | +------+------+------+------------+ | 1 | 1 | 1 | 2016-01-01 | | 1 | 0 | 4 | 2016-01-07 | | 1 | 1 | 2 | 2016-01-02 | | 1 | 0 | 1 | 2016-01-08 | | 1 | 1 | 3 | 2016-01-03 | | 1 | 0 | 2 | 2016-01-09 | | 1 | 1 | 4 | 2016-01-04 | | 1 | 1 | 1 | 2016-01-04 | | 1 | 1 | 2 | 2016-01-05 | | 1 | 1 | 3 | 2016-01-06 | +------+------+------+------------+ 10 rows in set (0.00 sec) 进行递归调用时,您正在使用+运算符,同时传递findPath +&#34; - &gt;&#34;作为一个论点。 + 运算符会导致连接,从而创建新的tempResult对象。基本上在每个递归级别,您将新的String对象传递到较低级别,并将每个级别的String变量放在较低级别的范围之外。

因此,您实际上无法访问上层递归的tempResult对象,即使您回溯,它也只会更新传递给该递归级别的String对象而不是属于上层的String,从未偶然开始!这就是为什么在第二种解决方案中不需要回溯的原因,因此没有完成。