一、题目
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
二、解决
1、DFS(回溯–先序遍历+路径记录)
思路:
- 先序遍历:根 - 左 - 右
- 路径记录:记录从根节点到当前节点的路径。当满足:(1)根节点到叶节点形成路径。(2)各节点值的和等于目标值sum,可将该路径加入结果列表。
这里附下DFS代码模板:
public List<Integer> dfs(Node root, int curLayer, List<Integer> result) {
// 终止条件
if (root == null || curlayer > n) return result; // 数据非法
if (curLayer.val == true) { // 满足条件
result.add(xxx); // xxx: node.val / curlayer / path
return result;
}
if (canCutBranch()) return result;
visited[root] = true; // 标记:处理当前顶点,记录为已访问
for (Node next : root) { // 遍历与当前顶点相邻的所有未访问顶点
visited[next] = true;
result.add(xxx) // 标记更改: 修改result/path/其他
dfs(next, curLayer + 1, result)
visited[next] = false;
result.remove(xxx) // 恢复更改: 还原result/path/其他
}
return result;
}
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
LinkedList<List<Integer>> res = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
recur(root, sum);
return res;
}
private void recur(TreeNode root, int sum) {
// Terminator
if(root == null) return;
path.add(root.val);
sum -= root.val;
if(sum == 0 && root.left == null && root.right == null) {
res.add(new LinkedList(path));
// return;
// 多一个return,就会提前跳出,导致path少删去一个节点,最终使得path比sum多一个节点,不再一一对应。
// 例子:
// 输入:
// [5,4,8,11,null,13,4,7,2,null,null,5,1]
// 22
// 输出:
// [[5,4,11,2],[5,4,8,4,5]]
recur(root.left, sum);
recur(root.right, sum);
path.removeLast();
}
}
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)。最坏情况下,此时上半部分退化为链表,下半部变成完全二叉树,且每一条路径都满足要求。
空间复杂度:
O
(
n
)
O(n)
O(n)
2、BFS
思路:
DFS是先从上往下遍历,BFS是一行一行遍历。
再附下BFS代码模板:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public List<List<Integer>> BFS(TreeNode root) {
List<List<Integer>> allResults = new ArrayList<>();
if (root == null) return allResults;
Queue<TreeNode> nodes = new LinkedList<>();
nodes.add(root);
while (!nodes.isEmpty()) {
int levelSize = nodes.size();
List<Integer> results = new ArrayList<>();
for (int i = 0; i < levelSize; i++) {
TreeNode currNode = nodes.poll();
results.add(currNode.val);
if (currNode.left != null) nodes.add(currNode.left);
if (currNode.right != null) nodes.add(currNode.right);
}
allResults.add(results);
}
return allResults;
}
代码:
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new ArrayList<>();
//如果节点为空直接返回
if (root == null)
return res;
//使用两个队列,一个存储结点,一个存储从更结点到当前节点的路径
Queue<TreeNode> queueNode = new LinkedList<>();
Queue<List<Integer>> queueList = new LinkedList<>();
//根节点入队
queueNode.add(root);
//根节点的路径入队
List<Integer> list = new ArrayList<>();
list.add(root.val);
queueList.add(list);
while (!queueNode.isEmpty()) {
//当前节点出队
TreeNode node = queueNode.poll();
//当前节点的路径出队
List<Integer> tempList = queueList.poll();
if (node.left == null && node.right == null && node.val == sum) {
//如果满足条件,就把路径存储到res中
res.add(tempList);
}
//左子节点不为空,左子节点和路径入队
if (node.left != null) {
tempList.add(node.left.val);
queueList.add(new ArrayList<>(tempList));
node.left.val += node.val;
queueNode.add(node.left);
tempList.remove(tempList.size() - 1);
}
//右子节点不为空,右子节点和路径入队
if (node.right != null) {
tempList.add(node.right.val);
queueList.add(new ArrayList<>(tempList));
node.right.val += node.val;
queueNode.add(node.right);
}
}
return res;
}
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
三、参考
1、面试题34. 二叉树中和为某一值的路径(回溯法,清晰图解)
2、路径总和 II
3、DFS,BFS共5种方式解决,2种击败了100%的用户
4、Simple DFS Java Solution
5、Java Solution: iterative and recursive
6、Another accepted Java solution