递归时值传递、引用传递的注意"/>
【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】递归时值传递、引用传递的注意
发布评论