leetcode 863. All Nodes Distance K in Binary Tree(二叉树中距离K的节点)

We are given a binary tree (with root node root), a target node, and an integer value K.

Return a list of the values of all nodes that have a distance K from the target node. The answer can be returned in any order.

Example 1:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2

Output: [7,4,1]

Explanation:
The nodes that are a distance 2 from the target node (with value 5)
have values 7, 4, and 1.
在这里插入图片描述
Note that the inputs “root” and “target” are actually TreeNodes.
The descriptions of the inputs above are just serializations of these objects.

给出一个二叉树,一个target节点,找出所有到target距离为K的节点。

思路:
参考了方法,两种思路

1 转化为无向图,用BFS
先把二叉树转为无向图,因为每个边都是双向的,所以要用一个HashSet保存访问过的node。
然后用BFS保存K步的node

class Solution {
    HashMap<TreeNode, List<TreeNode>> graph = new HashMap<>();
    
    public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
        List<Integer> result = new ArrayList<>();
        buildGraph(null, root);
        
        Queue<TreeNode> queue = new LinkedList<>();
        HashSet<TreeNode> visited = new HashSet<>();
        queue.add(target);
        visited.add(target);
        int k = 0;
        
        while(!queue.isEmpty() && k <= K) {
            int size = queue.size();
            for(int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                if(k == K) result.add(node.val);
                for(TreeNode child : graph.get(node)) {
                    if(visited.contains(child)) continue;
                    queue.offer(child);
                    visited.add(child);
                }
            }
            k++;
        }
        return result;
    }
    
    void buildGraph(TreeNode root, TreeNode child) {
        if(root != null) {
          if(!graph.containsKey(root)) {
            List<TreeNode> tmp = new ArrayList<>();
            graph.put(root, tmp);
          }
        
          if(child != null) {
            graph.get(root).add(child);
            if(!graph.containsKey(child)) {
                List<TreeNode> tmp = new ArrayList<>();
                graph.put(child, tmp);
            }
            graph.get(child).add(root);
                        
          }
        } else {
        //root本身要建一个空的list,否则会出现NullPointerException
            List<TreeNode> tmp = new ArrayList<>();
            graph.put(child, tmp);
        }
        if(child.left != null) buildGraph(child, child.left);
        if(child.right != null) buildGraph(child, child.right);        
    }
}

2 树的中序遍历递归
中序遍历要做两件事情,第一,要找到target的位置,第二,找到距离target为K的node

中序遍历不像无向图那样是双向的,它从上到下遍历,所以收集距离target为K的node时,只收集某个root下面的节点,不会再往上走。

那么如果像Example中那样,target在左子树,但是root.right中也有目标怎么办。
这时可以找到root.left到target的距离,设这个距离是dis_left,那么root到target的距离就是dis_left+1。root到root.right的距离是1,所以root.left到root.right的距离是dis_left+2。那么只需要向下收集 到root.right距离为K - (dis_left+2)的node就行了。

所以需要一个函数,又能中序遍历找target,又能返回target到当前root的距离。而且要用-1表示没有找到target。
还需要一个中序遍历向下收集距离root为d的node的函数,因为返回了距离之后又要再次向下找node
这两个函数都是在遍历过程中一旦发现距离target为K的node,就保存到结果list中。

class Solution {
    List<Integer> result = new ArrayList<>();
    public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
        if(root == null) return result;
        distance(root, target, K);
        return result;
    }
    
    int distance(TreeNode root, TreeNode target, int K) {
        if(root == null) return -1;
        if(root.val == target.val) {
            collect(target, K);
            return 0;
        }
        int left = distance(root.left, target, K);
        int right = distance(root.right, target, K);
        
        if(left >= 0) {
            if(left == K-1) result.add(root.val);
            collect(root.right, K-left-2);
            return (left+1);
        }
        if(right >= 0) {
            if(right == K-1) result.add(root.val);
            collect(root.left, K-right-2);
            return (right+1);
        }
        return -1;
    }
    
    void collect(TreeNode root, int d) {
        if(root == null || d < 0) return;
        if(d == 0) result.add(root.val);
        collect(root.left, d-1);
        collect(root.right, d-1);
    }
}

还有一种是用一个map装每个点和它到target的距离,
target本身到自己的距离是0,其他的依次+1,
统计好之后再用dfs遍历节点,当距离为k时装入结果。

class Solution {
    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        pathLength(map, root, target);
        List<Integer> res = new ArrayList<>();
        dfs(res, map, k, root, 0);
        return res;
    }

    private void dfs(List<Integer> res, Map<Integer, Integer> map, int k, TreeNode curr, int l) {
        if (curr == null) return;
        if (map.containsKey(curr.val)) l = map.get(curr.val);
        if (l == k) res.add(curr.val);
        dfs(res, map, k, curr.left, l + 1);
        dfs(res, map, k, curr.right, l + 1);
    }

    private int pathLength(Map<Integer, Integer> map, TreeNode curr, TreeNode target) {
        if (curr == null) return -1;
        if (curr == target) {
            map.put(curr.val, 0);
            return 1;
        }

        int left = pathLength(map, curr.left, target);
        if (left > 0) {
            map.put(curr.val, left);
            return left + 1;
        }

        int right = pathLength(map, curr.right, target);
        if (right > 0) {
            map.put(curr.val, right);
            return right + 1;
        }

        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值