栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【LeetCode】递归时值传递、引用传递的注意

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【LeetCode】递归时值传递、引用传递的注意

#LeetCode每日一题【二叉树专题】

在java中基本类型都是值传递,而非基本类型都是引用传递;当其作为参数在递归过程中,需要注意分支污染问题,以及是否需要回溯的问题

int作为参数传递

因为int是值传递,每次递归调用方法都是传入一个值,递归调用结束之后,并不会影响原来的值,即不存在分支污染问题

如:LeetCode104求根节点到叶节点数字之和

	int ans = 0;

    public int sumNumbers(TreeNode root) {
        getSum(root, 0);
        return ans;
    }

    private void getSum(TreeNode root, int sum) {
        if (root == null) return;
        sum = sum * 10 + root.val;
        if (root.left == null && root.right == null) {
            ans+=sum;
        }
        getSum(root.left, sum);
        getSum(root.right, sum);
    }

String作为参数传递

String本身是引用传递,但是他比较特殊,String是final的,每次+或者赋值其实都是生成了一个新的String对象,即在递归过程中也不存在分支污染问题,不需要回溯操作;

跟上面的int不同:如果有操作,则每次递归调用的时候都生成了一份新的String传入了

如:LeetCode257二叉树的所有路径

public List binaryTreePaths(TreeNode root) {
        List ans = new ArrayList<>();
        binaryTreePaths2(root, "", ans);
        return ans;
    }

    // string相加太慢了
    // 只是想说明下,直接使用String为什么不需要回溯,因为使用String的+的时候已经生成了一个新的对象了
    // 后面下一次递归传值的时候是新对象传入
    private void binaryTreePaths(TreeNode root, String res, List ans) {
        if (root == null) return;
        if (res.length() == 0) {
            res += root.val;
        } else {
            res = res + "->" + root.val;
        }
        if (root.left == null && root.right == null) {
            ans.add(res);
        }
        binaryTreePaths(root.left, res, ans);
        binaryTreePaths(root.right, res, ans);
    }

List作为参数传入

list是最容易犯错的一个点,有时候会很容易忽略将list作为参数传入之后,然后做了相应的修改,原方法的该list已经同步做了修改这点没有意识到。

在递归中也是一样,递归调用该方法的时候list做了修改,那返回到原来时在使用该list会同步保留该修改,即递归中分支污染问题,需要回溯的场景

如:LeetCode113路径总和 II

List> ans = new linkedList<>();

    public List> pathSum(TreeNode root, int targetSum) {
        linkedList res = new linkedList<>();
        pathSum(root, targetSum, res);
        return ans;
    }

    // 深度优先搜索+回溯
    private void pathSum(TreeNode root, int targetSum, linkedList res) {
        if (root == null) return;
        res.add(root.val);
        if (root.left == null && root.right == null) {
            // 叶子节点满足最终条件
            if (root.val == targetSum) {
                // 要new一个集合进去,不然后面会被同步修改
                ans.add(new linkedList<>(res));
            }
        }
        pathSum(root.left, targetSum - root.val, res);
        pathSum(root.right, targetSum - root.val, res);
        // 要回溯,把当前的节点从集合中去除
        res.pollLast();
    }

如果不想回溯的话,类似于String那种,可以在每次递归调用的时候生成一份新的list传入,这样每次调用操作的list之间互不影响(但存在集合copy的大量时间空间开销)

// 深度优先搜索+每次递归都生成一个新集合,保证不会干扰其他递归分支
    private void pathSum2(TreeNode root, int targetSum, linkedList res) {
        if (root == null) return;
        // 每次递归进来都重新new一个集合,这样能保证参数res不会在每次递归中相互干扰,也就不用回溯
        linkedList temp = new linkedList<>(res);
        temp.add(root.val);
        if (root.left == null && root.right == null) {
            if (root.val == targetSum) {
                ans.add(temp);
            }
        }
        pathSum2(root.left, targetSum - root.val, temp);
        pathSum2(root.right, targetSum - root.val, temp);
    }

总结

在递归过程中能够快速识别到是否会存在分支污染问题,是否需要回溯操作,尤其注意List的情况

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/749770.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号