1.题目
剑指 Offer 34. 二叉树中和为某一值的路径
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
提示:
节点总数 <= 10000
2.自我思路及实现
未AC
递归
DFS
递归
方法功能:获取树中和为某一值的路径中的所有节点
终止条件:节点为空
递归函数:子树sum = sum - 父节点值
当sum为零且左右子节点均为空时,表明找到了路径,将此路径存储起来
对左右子树进行递归
未实现的地方
- 如何将每条路径上的节点存储起来
- 如何存储多条路径
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if(root== null)
return new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
dfs(root, sum, path);
res.add(path);
return res;
}
void dfs(TreeNode root, int sum, LinkedList<Integer> path)
{
if(root == null)
return;
sum -= root.val;
if(sum == 0 && root.left == null && root.right == null)
path.add(root.val);
dfs(root.left, sum, path);
dfs(root.right, sum, path);
}
}
3.总结思路及实现
DFS递归
使用成员变量二维动态数组res作为返回值,链表path存储路径,这样就可以在递归的过程中存储节点值和返回需要的路径
dfs方法功能:获取树中和为某一值的路径中的所有节点
终止条件:节点为空时返回
递归函数:
1.路径更新:将当前节点值加入路径path
2.目标值更新: sum -=root.val
3.路径记录:当sum为零且左右子节点均为空时,表明找到了路径,将此路径存入res,注意要新建一个路径来存储,否则后序操作会影响已存入的路径
4.先序遍历:递归左右子节点
5.路径恢复:向上回溯时,需要将当前节点从path中移除
时间:N2,在最坏情况下,树的上半部分为链状,下半部分为完全二叉树(除最后一层外其余各层节点数都达到最大个数),并且从根节点到每一个叶子节点的路径都符合题目要求。此时,路径的数目为 O(N),并且每一条路径的节点个数也为 O(N),因此要将这些路径全部添加进答案中,时间复杂度为 O(N^2)
空间:N,栈最大深度为N
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
dfs(root, sum);
return res;
}
void dfs(TreeNode root, int sum)
{
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));
dfs(root.left, sum);
dfs(root.right, sum);
path.removeLast();
}
}
BFS,队列实现
当遍历到叶子节点,且此时路径值恰为目标值时,获得一条满足要求的路径
使用哈希表存储节点与其父节点的对应关系
使用两个队列,一个队列存储节点,另一个队列存储该节点对应的路径上的所有节点值的和,当和==sum时且为叶子节点时,输出其路径
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<List<Integer>> res = new LinkedList<>();
Map<TreeNode, TreeNode> map = new HashMap<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if(root == null)
return res;
Queue<TreeNode> nodeQue = new LinkedList<>(); //存储节点的队列
Queue<Integer> curSum = new LinkedList<>(); //存储当前节点和值的队列
nodeQue.offer(root);
curSum.offer(0);
while(!nodeQue.isEmpty())
{
TreeNode temp = nodeQue.poll();
int cur = curSum.poll() + temp.val;
if(cur == sum && temp.left == null && temp.right == null)
path(temp);
else
{
if(temp.left != null)
{
nodeQue.offer(temp.left);
curSum.offer(cur);
map.put(temp.left, temp);
}
if(temp.right != null)
{
nodeQue.offer(temp.right);
curSum.offer(cur);
map.put(temp.right, temp);
}
}
}
return res;
}
void path(TreeNode temp)
{
List<Integer> list = new LinkedList<>();
while(temp != null)
{
list.add(temp.val);
temp = map.get(temp);
}
Collections.reverse(list); //获得的路径是倒序的,需要反转
res.add(new LinkedList<>(list));
}
}
4.相关知识
- 先将思路写下来,不要只想,一步一步确定
- 树递归存储节点一般需要使用成员变量
- public LinkedList(Collection<? extends E> c):将c中元素复制到新链表中
- public ArrayList(Collection<? extends E> c):将c中元素复制到新动态数组中