首页 > 试题广场 >

距离是K的二叉树节点

[编程题]距离是K的二叉树节点
  • 热度指数:851 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个二叉树的根节点 root ,和一个目标节点的值 target ,和一个目标距离 k ,请你找出二叉树上所有与 target 距离是 k 的节点的值。



数据范围:二叉树的节点数满足 ,节点上的值在范围 [0,n) 内,每个节点的值各不相同。
示例1

输入

{3,5,2,4,6,0,7,1,8},5,2

输出

[1,8,2]

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
import java.util.*;

// 以节点target 为根,       下面第k层节点
// 以节点target 父节点 为根, 下面第k-1层节点
// 父父节点, k-2层 ...  循环
//
// Map存父节点
public class Solution {
    ArrayList<Integer> res = new ArrayList<>();  // 结果
    Set<TreeNode> parent = new HashSet<>(); // target及父节点

    public ArrayList<Integer> distanceKnodes (TreeNode root, int target, int k) {
        // BFS: 找到target节点及其父节点
        Map<TreeNode, TreeNode> map = new HashMap<>(); // 存父节点
        map.put(root, null);
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        TreeNode targetNode = null; // target节点
        while (!queue.isEmpty()) {
            TreeNode t = queue.poll();
            if (t.val == target) {
                targetNode = t;
                break;
            }
            if (t.left  != null) {
                map.put(t.left, t);
                queue.offer(t.left);
            }
            if (t.right != null) {
                map.put(t.right, t);
                queue.offer(t.right);
            }
        }
        // target及父节点
        TreeNode p = targetNode;
        while (p != null) {
            parent.add(p);
            p = map.get(p);
        }
        // 循环:target节点为根 下面k层节点, 父 k-1, 父父 k-2...
        if (k == 0) res.add(target); // k==0 特判target
        p = targetNode;
        while (p != null) {
            bfs(p, k, target); // 调用
            p = map.get(p);
            k--;
        }
        
        return res;
    }

    // BFS: 以root为根, 下面第k层节点 (排除target及其父节点那侧子树🍓)
    void bfs(TreeNode root, int k, int target) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int level = 0;
        while (!queue.isEmpty() && level <= k + 1) {
            level++;
            int size = queue.size();
            while (size-- > 0) {
                TreeNode t = queue.poll();
                if (level == k + 1) { // 下面第k层节点
                    res.add(t.val);
                }
                // 排除target及其父节点 那个子树分支(因为会重复计算,上去时已算过一部分路径了)
                if (t.left  != null && !parent.contains(t.left))  queue.offer(t.left);
                if (t.right != null && !parent.contains(t.right)) queue.offer(t.right);
            }
        }
    }
}

发表于 2025-04-12 11:54:55 回复(0)
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

/**
 * NC370 距离是K的二叉树节点
 * @author d3y1
 */
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param root TreeNode类
     * @param target int整型
     * @param k int整型
     * @return int整型一维数组
     */
    public ArrayList<Integer> distanceKnodes (TreeNode root, int target, int k) {
        // return solution1(root, target, k);
        return solution2(root, target, k);
    }

    private HashSet<Integer>[] adj;
    private boolean[] isVisited;
    private ArrayList<Integer> result = new ArrayList<>();
    private final int N = 1000;

    /**
     * 后序遍历 + 层序遍历
     * 
     * 图模型
     * 
     * @param root
     * @param target
     * @param k
     * @return
     */
    private ArrayList<Integer> solution1(TreeNode root, int target, int k){
        isVisited = new boolean[N];
        adj = new HashSet[N];
        for(int i = 0; i < N; i++){
            adj[i] = new HashSet<>();
        }

        postOrder(root);
        levelOrder(target, k);

        return result;
    }

    /**
     * 递归: 后序遍历
     * @param root
     */
    private void postOrder(TreeNode root){
        if(root == null){
            return;
        }

        postOrder(root.left);
        postOrder(root.right);

        if(root.left != null){
            adj[root.val].add(root.left.val);
            adj[root.left.val].add(root.val);
        }
        if(root.right != null){
            adj[root.val].add(root.right.val);
            adj[root.right.val].add(root.val);
        }
    }

    /**
     * 队列: 层序遍历
     * @param target
     * @param k
     */
    private void levelOrder(int target, int k){
        Queue<Integer> queue = new LinkedList<>();
        isVisited[target] = true;
        queue.offer(target);

        int curr;
        int size;
        int level = 0;
        boolean isFound = false;
        while(!queue.isEmpty()){
            level++;
            size = queue.size();
            while(size-- > 0){
                curr = queue.poll();
                for(int next: adj[curr]){
                    if(!isVisited[next]){
                        isVisited[next] = true;
                        if(level == k){
                            isFound = true;
                            result.add(next);
                        }else{
                            queue.offer(next);
                        }
                    }
                }
            }
            if(isFound){
                break;
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////

    private ArrayList<Integer> list = new ArrayList<>();
    private HashMap<Integer,TreeNode> parentMap = new HashMap<>();

    /**
     * 层序遍历 + 前序遍历
     * @param root
     * @param target
     * @param k
     * @return
     */
    private ArrayList<Integer> solution2(TreeNode root, int target, int k){
        if(root == null){
            return list;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        parentMap.put(root.val, null);


        TreeNode node,cNode,pNode;
        while(!queue.isEmpty()){
            node = queue.poll();
            if(node.val == target){
                if(k == 0){
                    list.add(node.val);
                    return list;
                }
                downKnodes(node, k);
                cNode = node;
                pNode = parentMap.get(cNode.val);
                while(pNode!=null && k>0){
                    upKnodes(cNode, pNode, --k);
                    cNode = pNode;
                    pNode = parentMap.get(cNode.val);
                }

                return list;
            }
            if(node.left != null){
                parentMap.put(node.left.val, node);
                queue.offer(node.left);
            }
            if(node.right != null){
                parentMap.put(node.right.val, node);
                queue.offer(node.right);
            }
        }

        return list;
    }

    /**
     * 向上遍历
     * @param cNode
     * @param pNode
     * @param k
     */
    private void upKnodes(TreeNode cNode, TreeNode pNode, int k){
        if(k == 0){
            list.add(pNode.val);
            return;
        }

        if(pNode.left!=null && pNode.left.val!=cNode.val){
            downKnodes(pNode.left, k-1);
        }

        if(pNode.right!=null && pNode.right.val!=cNode.val){
            downKnodes(pNode.right, k-1);
        }
    }

    /**
     * 向下遍历
     * @param root
     * @param k
     */
    private void downKnodes(TreeNode root, int k){
        preOrder(root, k);
    }

    /**
     * 前序遍历
     * @param root
     * @param k
     */
    private void preOrder(TreeNode root, int k){
        if(root == null){
            return;
        }

        if(k == 0){
            list.add(root.val);
            return;
        }

        preOrder(root.left, k-1);
        preOrder(root.right, k-1);
    }
}

发表于 2025-01-23 15:17:19 回复(0)
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param target int整型 
     * @param k int整型 
     * @return int整型ArrayList
     */
    public ArrayList<Integer> distanceKnodes(TreeNode root, int target, int k) {
        // write code here
        if (root == null) {
            return new ArrayList<>();
        }
        // 最终返回的结果
        Set<Integer> finalRes = new HashSet<>();
        // 记录dfs遍历的所有路径
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        // dfs遍历路径
        dfs(root, new ArrayList<>(), result);

        // 记录已经处理过的节点,理论上后续处理过的节点所在的路径无需再次处理
        ArrayList<Integer> processNode = new ArrayList<>();
        int father = target;
        while (k > 0) {
            judgeNode(finalRes, k--, result, processNode, father);
            // 加入到已处理集合
            processNode.add(father);
            // 找到新的父节点
            father = getFather(result, father);
        }
        return new ArrayList<>(finalRes);
    }

    private boolean alreadyChoose(ArrayList<Integer> processNodes, ArrayList<Integer> integers) {
        for (Integer processNode : processNodes) {
            if (integers.contains(processNode)) {
                return true;
            }
        }
        return false;
    }

    private void judgeNode(Set<Integer> finalRes, int k, ArrayList<ArrayList<Integer>> result,
                           ArrayList<Integer> processFather, int father) {
        for (ArrayList<Integer> integers : result) {
            if (alreadyChoose(processFather, integers)) {
                continue;
            }
            // 根节点,仅需处理未处理过的孩子
            if (father == -1) {
                if (k < integers.size()) {
                    finalRes.add(integers.get(k));
                }
            } else {
                // 非根节点,需处理包含father节点的路径
                if (integers.contains(father)) {
                    int index = integers.indexOf(father);
                    if (index + k < integers.size()) {
                        finalRes.add(integers.get(index + k));
                    }
                    if (index - k >= 0) {
                        finalRes.add(integers.get(index - k));
                    }
                }
            }

        }
    }

    /**
     * 获取当前处理节点的父节点
     * @param result
     * @param target
     * @return
     */
    private int getFather(ArrayList<ArrayList<Integer>> result, int target) {
        for (ArrayList<Integer> res : result) {
            if (res.contains(target)) {
                int index = res.indexOf(target);
                if (index - 1 >= 0) {
                    return res.get(index - 1);
                }
            }
        }
        // 已经是树根了,无父节点
        return -1;
    }

    private void dfs(TreeNode root, ArrayList<Integer> list, ArrayList<ArrayList<Integer>> result) {
        list.add(root.val);

        if (root.left == null && root.right == null) {
            result.add(new ArrayList<>(list));
            return;
        }

        if (root.left != null) {
            dfs(root.left, list, result);
            list.remove(list.size() - 1);
        }
        if (root.right != null) {
            dfs(root.right, list, result);
            list.remove(list.size() - 1);
        }
    }
}

发表于 2022-04-17 15:28:50 回复(0)