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

编程入门 行业动态 更新时间:2024-10-26 12:21:51

【LeetCode】<a href=https://www.elefans.com/category/jswz/34/1771140.html style=递归时值传递、引用传递的注意"/>

【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<String> binaryTreePaths(TreeNode root) {List<String> ans = new ArrayList<>();binaryTreePaths2(root, "", ans);return ans;}// string相加太慢了// 只是想说明下,直接使用String为什么不需要回溯,因为使用String的+的时候已经生成了一个新的对象了// 后面下一次递归传值的时候是新对象传入private void binaryTreePaths(TreeNode root, String res, List<String> 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<List<Integer>> ans = new LinkedList<>();public List<List<Integer>> pathSum(TreeNode root, int targetSum) {LinkedList<Integer> res = new LinkedList<>();pathSum(root, targetSum, res);return ans;}// 深度优先搜索+回溯private void pathSum(TreeNode root, int targetSum, LinkedList<Integer> 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<Integer> res) {if (root == null) return;// 每次递归进来都重新new一个集合,这样能保证参数res不会在每次递归中相互干扰,也就不用回溯LinkedList<Integer> 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的情况

更多推荐

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

本文发布于:2024-02-17 06:44:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1693059.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:递归   LeetCode

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!