二叉树-距离是K的二叉树节点(hard)

目录

一、问题描述

二、解题思路

1.总体思路(DFS+BFS结合)

2.下面举具体例子来对思路进行解释

(1)返回值在一侧的情况

(2)返回值在两侧的情况

三、代码实现

四、刷题链接


一、问题描述

二、解题思路

1.总体思路(DFS+BFS结合)

        使用深度遍历DFS算法获得目标结点所在路径(不包含目标结点和根节点),保存在ArrayList中,同时我们可以根据下标可以知道祖先结点距离目标结点的距离(dis),根据这个差值(k-dis),我们就可以使用广度优先遍历(层序遍历BFS算法)来求祖先节点的第(k-dis)层的子孙结点

2.下面举具体例子来对思路进行解释

返回值结点可能在根节点单侧或双侧的情况

(1)返回值在一侧的情况

再来看一个例子target=1,k=2时:

(2)返回值在两侧的情况

画红色框框的是需要比较的几个关键结点。

三、代码实现

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 {
    int depth=0;
    TreeNode resNode=new TreeNode(-1);
    HashSet<Integer> findSet=new HashSet<>();
    ArrayList<Integer> arr = new ArrayList<>();
    ArrayList<TreeNode> nodes=new ArrayList<>();
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param target int整型 
     * @param k int整型 
     * @return int整型一维数组
     */
    public ArrayList<Integer> distanceKnodes (TreeNode root, int target, int k) {
        boolean isSide=false;
        boolean isleft=false;
        if(k==0){
            arr.add(target);
            return arr;
        }
        if(root.val==target){//直接执行bfs即可
            bfs(root.left,k-1);
            bfs(root.right,k-1);
            return arr;
        }
        // 先检查是否在左侧
        dfs(root.left,target,1);
        if(depth!=0){
            isleft=true;
        }else{
            dfs(root.right,target,1);
        }
        if(depth<k){
            isSide=false;
        }else{
            isSide=true;
        }

        if(isSide){//结果都在根节点一侧
            //遍历target子孙结点
            bfs(resNode,k);

            //如果是根节点
            if(k==nodes.size()+1){
                arr.add(root.val);
            }
            for(int i=0;i<nodes.size();i++){
                if(k==i+1){//如果祖先结点路径上存在距离为k的节点,也要返回
                    arr.add(nodes.get(i).val);
                }
                //祖先结点的孩子结点存在距离为k的结点返回(注意避开目标结点所在路径)
                if(nodes.get(i).left!=null&&!findSet.contains(nodes.get(i).left.val)){
                    bfs(nodes.get(i).left,k-i-1-1);
                }
                if(nodes.get(i).right!=null&&!findSet.contains(nodes.get(i).right.val)){
                    bfs(nodes.get(i).right,k-i-1-1);
                }
            }
        }else{//结果分散在根节点两侧
            int diff=k-depth;
            if(isleft){
                //遍历右侧深度为diff-1的结点
                bfs(root.right,diff-1);
            }else{
                //遍历右侧深度为diff-1的结点
                bfs(root.left,diff-1);
            }
            //遍历target子孙结点
            bfs(resNode,k);

            //遍历祖先节点
            for(int i=0;i<nodes.size();i++){
                if(nodes.get(i).left!=null&&!findSet.contains(nodes.get(i).left.val)){
                    bfs(nodes.get(i).left,k-i-1-1);
                }
                if(nodes.get(i).right!=null&&!findSet.contains(nodes.get(i).right.val)){
                    bfs(nodes.get(i).right,k-i-1-1);
                }
                
            }
        }
        
        return arr; 
    }
    //遍历第depth层的结点
    public void bfs(TreeNode root,int depth){
        if(root==null){
            return;
        }
        int layernum=0;//深度是从0开始的
        Queue<TreeNode> nowqueue=new LinkedList<>();
        nowqueue.offer(root);
        int nowlayerNodenum=1;//当前层的剩余结点数量
        int nextlayerNodenum=0;//下一层的结点数量
        while(!nowqueue.isEmpty()){
            TreeNode nownode=nowqueue.poll();
            if(layernum==depth){
                arr.add(nownode.val);
            }
            nowlayerNodenum--;
            
            if(nownode.left!=null){
                nowqueue.offer(nownode.left);
                nextlayerNodenum++;
            }
            if(nownode.right!=null){
                nowqueue.offer(nownode.right);
                nextlayerNodenum++;
            }

            if(nowlayerNodenum==0){
                nowlayerNodenum=nextlayerNodenum;
                layernum++;//开启下一层的遍历操作
                nextlayerNodenum=0;
                if(layernum>depth){
                    break;
                }
            }
        }
    }
    public boolean dfs(TreeNode root,int target,int nowdepth){
        if(root==null){
            return false;
        }
        if(root.val==target){
            depth=nowdepth;
            resNode=root;
            findSet.add(root.val);
            return true;
        }else{
            boolean leftbool=dfs(root.left,target,nowdepth+1);
            boolean rightbool=dfs(root.right,target,nowdepth+1);
            if(leftbool||rightbool){
                nodes.add(root);
                findSet.add(root.val);
                return true;
            }else{
                return false;
            }
        }
    }
}

四、刷题链接

距离是K的二叉树节点_牛客题霸_牛客网

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值