🐌1. 题目描述

:::info 给定三个参数

  1. 二叉树的头节点head,
  2. 树上某个节点target,
  3. 正整数K

从target开始,可以向上走或者向下走,返回于target的距离是K的所有节点。 ::: 示例


💡2. 解决思路

  1. 从二叉树的指定节点target开始,既可以向上也可以向下走,说明需要对该二叉树结构进行功能增强,每个节点应该知道自己的父节点是谁,因此需要个结构保存每个节点的父节点信息的对应关系,这样达到一个无向图的效果。
  2. 然后基于增强功能的树结构,查找距离target节点长度为K的所有节点,图的宽度优先遍历(队列实现),找到第K层的所有节点就是输出答案。
  3. 为了方便输出某一层的所有的节点,对入队的一层的所有节点进行批处理操作。
  4. 为了避免节点重复入栈,需要设置一个Set集合,用于节点的注册,避免重复入栈。

🚩3. 代码实现

  1. public class Code08_DistanceKNodes {
  2. // 二叉树结构
  3. public static class Node {
  4. public int value;
  5. public Node left;
  6. public Node right;
  7. public Node(int v) {
  8. value = v;
  9. }
  10. }
  11. public static List<Node> distanceKNodes(Node root, Node target, int K) {
  12. // 存储节点的父子关系
  13. HashMap<Node, Node> parents = new HashMap<>();
  14. // 头节点的父节点为null
  15. parents.put(root, null);
  16. // 构建root二叉树的父子节点关系
  17. createParentMap(root, parents);
  18. // 队列用于实现宽度优先遍历
  19. Queue<Node> queue = new LinkedList<>();
  20. // 注册集合用于存放访问过的节点信息
  21. HashSet<Node> visited = new HashSet<>();
  22. // 基于二叉树结构和父子关系映射表map来实现从target节点开始的宽度优先遍历
  23. queue.offer(target); // target入队
  24. visited.add(target); // 将入队的注册到集合中
  25. int curLevel = 0;
  26. // 存放返回结果
  27. List<Node> ans = new ArrayList<>();
  28. while (!queue.isEmpty()) {
  29. // 当前层的节点个数
  30. int size = queue.size();
  31. // 对同层的节点进行同批处理
  32. while (size-- > 0) {
  33. Node cur = queue.poll();
  34. // 如果是K层则加入到结果中,K层表示距离为target节点距离为K
  35. if (curLevel == K) {
  36. ans.add(cur);
  37. }
  38. if (cur.left != null && !visited.contains(cur.left)) {
  39. visited.add(cur.left);
  40. queue.offer(cur.left);
  41. }
  42. if (cur.right != null && !visited.contains(cur.right)) {
  43. visited.add(cur.right);
  44. queue.offer(cur.right);
  45. }
  46. if (parents.get(cur) != null && !visited.contains(parents.get(cur))) {
  47. visited.add(parents.get(cur));
  48. queue.offer(parents.get(cur));
  49. }
  50. }
  51. curLevel++;
  52. if (curLevel > K) {
  53. break;
  54. }
  55. }
  56. return ans;
  57. }
  58. /**
  59. * 递归创建父子对应关系
  60. * @param cur 当前节点
  61. * @param parents 存储指定父子节点的对应关系,key为子节点,value为父节点
  62. */
  63. public static void createParentMap(Node cur, HashMap<Node, Node> parents) {
  64. if (cur == null) {
  65. return;
  66. }
  67. if (cur.left != null) {
  68. parents.put(cur.left, cur);
  69. createParentMap(cur.left, parents);
  70. }
  71. if (cur.right != null) {
  72. parents.put(cur.right, cur);
  73. createParentMap(cur.right, parents);
  74. }
  75. }
  76. // 测试
  77. public static void main(String[] args) {
  78. Node n0 = new Node(0);
  79. Node n1 = new Node(1);
  80. Node n2 = new Node(2);
  81. Node n3 = new Node(3);
  82. Node n4 = new Node(4);
  83. Node n5 = new Node(5);
  84. Node n6 = new Node(6);
  85. Node n7 = new Node(7);
  86. Node n8 = new Node(8);
  87. n3.left = n5;
  88. n3.right = n1;
  89. n5.left = n6;
  90. n5.right = n2;
  91. n1.left = n0;
  92. n1.right = n8;
  93. n2.left = n7;
  94. n2.right = n4;
  95. Node root = n3;
  96. Node target = n5;
  97. int K = 2;
  98. List<Node> ans = distanceKNodes(root, target, K);
  99. for (Node o1 : ans) {
  100. System.out.println(o1.value);
  101. }
  102. }
  103. }

🔑4. 考点

二叉树遍历图的深度优先遍历