回溯法在二叉树递归算法中很常用,就现在的理解来看回溯的作用主要是在递归调用之后保留当前层的状态,有两道题对我有一些启发。
104.二叉树的最大深度
本题有递归和迭代两种解法,此处只讨论递归法
class Solution {
int max = 0;
public int maxDepth(TreeNode root) {
if(root ==null) {
return 0;
}
getDepth(root, 1);
return max;
}
public void getDepth(TreeNode node, int depth) {
if(node == null) {
return;
}
if(depth > max) {
max = depth;
}
depth++;
getDepth(node.left, depth);
getDepth(node.right, depth);
depth--;//在此处回溯
}
}
如上段代码中的最后几行,先对depth++传到下轮递归中去,在调用完递归之后再将depth还原回本层真正的高度。
一般习惯的写法如下,这里其实隐含了回溯
getDepth(node.left, depth++);
getDepth(node.right, depth++);//实际隐含了回溯。
递归求高度应该是回溯法最简单的应用场景,后面一题稍微复杂一些。
113.路径总和II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。
本题是112.路径总和的升级版,需要返回所有满足条件的路径。
先看代码
class Solution {
int maxDeep = 0;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>>res = new ArrayList<>();
List<Integer>list = new ArrayList<>();
ans(root, targetSum, list, res);
return res;
}
public void ans(TreeNode node, int targetSum, List<Integer>list, List<List<Integer>>res) {
if(node == null) {
return;
}
if(node.left == null && node.right == null && targetSum == node.val) {
list.add(node.val);
res.add(new ArrayList(list));//由于res存储的是list的引用,为防止后续修改印象前面的数据此处需要new一个新的列表
list.remove(list.size()-1);
return;
}
list.add(node.val);
// if(node.left != null) {
ans(node.left, targetSum-node.val, list, res);
// list.remove(list.size()-1);
// }
// if(node.right != null) {
ans(node.right, targetSum-node.val, list, res);
list.remove(list.size()-1);
// }
}
}
在本题的ans函数中我们需要在每层递归中保存节点值并判断该节点是否是叶子节点。若该节点是叶子节点再判断列表中的数据和是否等于targetNum若等于则将列表保存到res列表中。在递归保存节点值的过程中使用了回溯,即最后几行,删除最后一个元素的目的是还原本层递归状态以免影响返回列表内容。