java中的显式回溯与隐式回溯思考

 用非常经典的一个力扣题目来理解显式回溯与隐式回溯。

  113. 路径总和 II


class Solution {

    List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<Integer> path = new ArrayList<>();
        findPath(root,targetSum,path);
        return res;
    }

    private void findPath (TreeNode root, int targetSum, List<Integer>path){
        if(root == null) return;
        path.add(root.val);
        // System.out.println(path);
        targetSum -= root.val;
        // System.out.println("+" + targetSum);
        if(root.left == null && root.right == null && targetSum == 0){
            res.add(new ArrayList(path));
        }
        findPath(root.left, targetSum, path);
        findPath(root.right, targetSum, path);
        path.remove(path.size() - 1);
    }
}

其中java是值传递,方法内的int和String之类的因此都是固定的(String是由于别的方法就算改变这个String,也是另外生成一个新的String,int则是值传递),而像ArrayList这些(比如递归回溯时候的path),值传递是一个地址,别的方法改变了,那就要回溯,否则方法栈回溯的时候,方法对应的变量就发生了变化。

所以上面的int不需要显式回溯,List需要显式回溯,且List一直在变,所以加入结果集合中必须建立一个目标副本,否则会加入一个空List。

回溯的其他思考我是看Doge Chen的博客递归回溯 值传递看懂了。

来看一下这题,下面两种回溯都是对的,可问题是为啥一个弹出两次,一个if一次,而下面的java代码只要最后写一次,其实问题就出在最后一次加入结果集的时候,上面的代码执行到叶子节点时候,明显不会执行下面的if语句里面的弹出回溯,而java的则会执行一次回溯。重点还是分析是不是有进有出,进出的总次数,主要分析第一次和最后一次。

if(root->left!=NULL) {
       dfs(root->left, sum); 
       path.pop_back();
       }
if(root->right!=NULL) {
       dfs(root->right, sum); 
       path.pop_back();
       }
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<Integer> path = new ArrayList<>();
        findPath(root,path,targetSum);
        return res;

    }
    public void findPath(TreeNode root,List<Integer> path,int targetSum){
        if(root == null){
            return;
        }
        path.add(root.val);
        if(root.left == null && root.right == null && targetSum == root.val){
            res.add(new ArrayList(path));
        }
        findPath(root.left,path,targetSum - root.val);
        findPath(root.right,path,targetSum - root.val);
        path.remove(path.size()-1);
    }
}

总结:
String在同一个方法内引用的内容固定,也就是递归下去的两个方法内参数内容是固定的,参见隐式回溯代码,不需要进行直接的回溯,两个方法内参数依然是那个String,而这题需要String发生了改变,同一个方法内第二次调用时候,String应该已经减去许多,这时候需要发生变化就定义一个全局变量,不走方法内值传递。走的是全局引用,一旦发生改变,就是新创建一个对象,引用的指向也发生改变。
而ArrayList这些可以走值传递,但是又不想发生变化时,就需要回溯。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值