解题思路
首先每个结点找到它的父结点然后存储在hashmap<TreeNode(儿子),TreeNode(父亲)>中根节点没有父亲,所以不存入里面.
然后我们这时候就可以把目标节点target看成一个新的根节点,这时候就是一个新树,距离它为K的结点也就是处在第K+1层的结点(根在第一层),这时候我们只需采用层序遍历,找到第K+1层的所有结点即可。
需要注意的是,我们的遍历只能从target开始一直向下一个方向的遍历,所以遇到原来target的父节点时,不能再返回来左右子树遍历了,也就是父节点只能添加一次,所以用一个set来存储已经添加的结点,再次遍历时,要看结点是否已经在set中,不在才能继续遍历,否则跳过。
package LeetCode.FiveHundredOneToOneThousand;
import LeetCode.TreeNode;
import java.util.*;
public class EightHundredAndSixtyThree {
// 对所有节点添加一个指向父节点的引用,之后做广度优先搜索,找到所有距离 target 节点 K 距离的节点。
Map<TreeNode, TreeNode> parent;
public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
parent = new HashMap<>();
dfs(root,null);
// 用队列记录
Queue<TreeNode> queue = new LinkedList<>();
queue.add(null);
queue.add(target);
// set是为了方便查询是否已经将节点存入了,防止重复
Set<TreeNode> set = new HashSet<>();
set.add(target);
set.add(null);
int dist = 0;
while (!queue.isEmpty()){ // 队列不为空时进行循环
TreeNode node = queue.poll();// 出栈
if (node == null){ // 当node为空说明已经将距离为dist的节点遍历完了
if (dist == k){ // 此时判断距离target的距离
List<Integer> ans = new ArrayList<>();
for (TreeNode n : queue)
ans.add(n.val);
return ans;
}
queue.offer(null);// 不相等的话就把这一层用null隔离
dist++;
}else {
// 判断set是否包含有node的左右节点,如果不包含将其放入set和queue
if (!set.contains(node.left)){
set.add(node.left);
queue.offer(node.left);
}
if (!set.contains(node.right)){
set.add(node.right);
queue.offer(node.right);
}
// 找出node的父节点,若此节点不在set中则将其放入set和queue中
TreeNode par = parent.get(node);
if (!set.contains(par)){
set.add(par);
queue.offer(par);
}
}
}
return new ArrayList<Integer>();
}
private void dfs(TreeNode root, TreeNode par){
// 将所有的节点都存入parent中并且存入它的父节点
if (root != null){
parent.put(root, par);
dfs(root.left, root);
dfs(root.right,root);
}
}
}