ningendo

回溯法5,在二叉树中的应用,递归的栈特性

一.题源

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

 

二.递归的栈特性

  先看下面的一个链表的例子

 

public class LinkListTest2 {
    public static void main(String[] args) {

        ListNode root = new ListNode(0);
        ListNode cur = root;
        for (int i = 1; i < 5; i++) {
            ListNode node = new ListNode(i);
            cur.setNext(node);
            cur = node;
        }

        LinkListUtil.displayList(root);

        List<Integer> list = new ArrayList<>();
        backTrace(root,list);

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

    private static void backTrace(ListNode node, List<Integer> list){
        if(node==null){
            return;
        }
        //相当于把数据压入栈
        list.add(node.getVal());
        System.out.print(list.size()+",");
        backTrace(node.getNext(),list);
        //数据出栈
        System.out.print(list.size()+",");
        list.remove(list.size()-1);
    }
}

 

输出:

0->1->2->3->4->
1,2,3,4,5,5,4,3,2,1,

 

三.递归的图解分析

 

 从上述结果可以看出,递归方法后面的方法,会随着递归函数的返回,逐一的从栈帧中弹出来并执行。

所以在递归中使用集合,也就形成了压栈和出栈的效果

 

四.题集的代码

  基于上述思想,本题的答案也可以想出来了。

 

public class Solution {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(5);

        TreeNode left1 = new TreeNode(4);
        TreeNode left2 = new TreeNode(11);
        TreeNode left3 = new TreeNode(7);
        TreeNode right3 = new TreeNode(2);

        left2.setLeft(left3);
        left2.setRight(right3);
        left1.setLeft(left2);

        TreeNode right1 = new TreeNode(8);
        TreeNode rleft2 = new TreeNode(13);
        TreeNode rRight3 = new TreeNode(4);
        TreeNode rLeft4 = new TreeNode(5);
        TreeNode rRight4 = new TreeNode(1);

        right1.setLeft(rleft2);
        right1.setRight(rRight3);
        rRight3.setLeft(rLeft4);
        rRight3.setRight(rRight4);

        root.setLeft(left1);
        root.setRight(right1);

        String p = "";
        BTUtils.printAllPath(root,p);
        System.out.println(p);

        ArrayUtils.displayArrayList(pathSum(root,22));

    }

    public static List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> list = new ArrayList<>();
        if(root==null){
            return list;
        }
        backTrace(list,new ArrayList<>(),root,sum,0);
        return list;
    }

    private static void backTrace(List<List<Integer>> result,List<Integer> list,TreeNode node,int sum,int innerSum){
        if(node!=null && node.getLeft()==null && node.getRight()==null){
            innerSum+=node.getVal();
            if(sum==innerSum){
                list.add(node.getVal());
                result.add(new ArrayList<>(list));
                list.remove(list.size()-1);
            }
            return;
        }
        if(node==null){
            return;
        }
        int val = innerSum + node.getVal();
        list.add(node.getVal());
        if(node.getLeft()!=null){
            backTrace(result,list,node.getLeft(),sum,val);
        }

        if(node.getRight()!=null){
            backTrace(result,list,node.getRight(),sum,val);
        }
        list.remove(list.size()-1);
    }
}

 

输出

5->4->11->7
5->4->11->2
5->8->13
5->8->4->5
5->8->4->1

[
    [5,4,11,2],
    [5,8,4,5]
]

 

五.题解的图解分析

 

 总之就是在递归方法之后执行的方法,有点像倒过来执行一样,就是从递归的最深处开始,逐一的执行,并返回上一个调用处。

模板如下,

list.add(ele);

backTrace(list,1);
backTrace(list,2);
backTrace(list,3);
//.....

list.remove();

//不考虑的递归的情况下,可以想象成这样
public void solve(){
  Stack<
Integer> stack = new Stack<>();
  stack.push(ele);
  excute(stack);
stack.pop();
}

public void excute(
Stack<Integer> stack){
  //do something
}

 

 

六.总结

   要注意的是,最好别在回溯和递归的方法写过于复杂的逻辑,要不然数据很容易计算出错。

 

posted on 2020-11-09 01:59  Lunamonna  阅读(82)  评论(0编辑  收藏  举报

导航