给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。
返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree
提示:
给定的树是非空的。
树上的每个结点都具有唯一的值 0 <= node.val <= 500 。
目标结点 target 是树上的结点。
0 <= K <= 1000.
解题思路:
1、判断当前根节点是否是target这个节点,如果是,直接调用方法,查找左右子树中距离这个节点为k的子节点。如果不是,那么就执行步骤2.
2、在当前节点中查找target的父节点parent,如果parent为null,说明这棵树中没有target这个节点,否则如果可以找到target的父节点的时候,那么判断target是parent的哪一个子节点,然后调用方法查找距离为k的子节点,这时候找到的是target的子节点,但是实际结果还可能包括target的父节点甚至是父节点的其他子节点。所以这时候进入递归,重新调用方法distanceK(root,parent,k - 1),查找距离parent为k - 1的节点。但是递归查找距离parent为k - 1的时候需要注意一点,访问的子节点不可以是已经访问过的,需要标记哪些顶点已经访问过了,所以在将target的子节点添加到列表之后,都需要将target变成null,表示已经访问过了。
如果仍旧不清楚,请看下面的演示过程:
对应的代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<Integer> list = new ArrayList<Integer>();
public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
if(root == target){
//如果根节点就是target这个节点,那么从它的左右子树中查找距离为K的节点
//这时候不在需要执行递归了,这也是为什么没有写递归结束的条件,程序依旧不会发生报错的原因
findDistancdK(root,k);
}else{
TreeNode parent = findTargetTreeNode(root,target);//获取值为target的节点的父节点
if(parent != null){
//判断target是parent的左子节点还是右子节点
if(parent.left != null && parent.left == target){
//target是parent的左子节点,那么调用方法获取距离target为k的子节点,然后标记这个节点已经访问过了
findDistancdK(parent.left, k);
parent.left = null;//标记这个顶点已经访问过了,那么递归distance(root,parent,k - 1)的时候就不会再访问这个节点了
}else{
//target是parent的右子节点,调用方法获取距离target为k的子节点,然后标记已经访问过了
findDistancdK(parent.right,k);
parent.right = null;//标记这个顶点已经访问过了,那么递归distance(root,parent,k - 1)的时候就不会再访问这个节点了
}
distanceK(root,parent,k - 1);//递归,获取距离parent为k - 1的节点
}
}
return list;
}
//获取target的父节点
public TreeNode findTargetTreeNode(TreeNode root,TreeNode target){
if(root == null)//如果root为空,那么将其root返回,表示这棵树没有target这个节点
return root;
if(root.left != null && root.left == target)
return root;
if(root.right != null && root.right == target)
return root;
TreeNode left = findTargetTreeNode(root.left,target);
if(left != null)//如果能在左子树中找到target的父节点,那么直接将其返回
return left;
TreeNode right = findTargetTreeNode(root.right,target);
if(right != null)//能在右子树中找到target的父节点
return right;
return null;
}
//获取距离root为k的左右子节点
public void findDistancdK(TreeNode root,int k){
if(root != null){
if(k == 0){
list.add(root.val);//如果k变成了0,那么将当前的节点添加到列表中,然后返回到上一层递归
return;
}
//如果k不为0,那么就往当前的左右子节点中查找
findDistancdK(root.left,k - 1);
findDistancdK(root.right,k - 1);
}
}
}
运行结果:
但是仔细分析下面的代码,发现递归并没有结束递归的条件,程序依旧不会发生报错,这是为什么呢?
public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
if(root == target){
//当root等于target的时候,在root的左右子树中查找距离root为k的节点,这时候不在进行递归,结束了递归
findDistancdK(root,k);
}else{
TreeNode parent = findTargetTreeNode(root,target);
if(parent != null){
if(parent.left != null && parent.left == target){
findDistancdK(parent.left, k);
parent.left = null;
}else{
findDistancdK(parent.right,k);
parent.right = null;
}
distanceK(root,parent,k - 1);//递归,获取距离parent为k - 1的节点
}
}
return list;
}
原因就在于我们每次递归查找距离parent为k - 1的节点,那么它是往上查找的,这时候必然会使得根节点等于target,这时候不会再进入递归了,所以就不需要再多想是否判断k的取值,从而结束递归了。