LeetCode 二叉树中所有距离为K的节点

给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。

返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree
在这里插入图片描述
提示:

给定的树是非空的。
树上的每个结点都具有唯一的值 0 <= node.val <= 500 。
目标结点 target 是树上的结点
0 <= K <= 1000.

解题思路:
1、判断当前根节点是否是target这个节点,如果是,直接调用方法,查找左右子树中距离这个节点为k的子节点。如果不是,那么就执行步骤2.
2、在当前节点中查找target的父节点parent,如果parent为null,说明这棵树中没有target这个节点,否则如果可以找到target的父节点的时候,那么判断target是parent的哪一个子节点,然后调用方法查找距离为k的子节点,这时候找到的是target的子节点,但是实际结果还可能包括target的父节点甚至是父节点的其他子节点。所以这时候进入递归,重新调用方法distanceK(root,parent,k - 1),查找距离parent为k - 1的节点。但是递归查找距离parent为k - 1的时候需要注意一点,访问的子节点不可以是已经访问过的,需要标记哪些顶点已经访问过了,所以在将target的子节点添加到列表之后,都需要将target变成null,表示已经访问过了。

如果仍旧不清楚,请看下面的演示过程:
在这里插入图片描述

对应的代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List<Integer> list = new ArrayList<Integer>();
    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        if(root == target){
        //如果根节点就是target这个节点,那么从它的左右子树中查找距离为K的节点
        //这时候不在需要执行递归了,这也是为什么没有写递归结束的条件,程序依旧不会发生报错的原因
            findDistancdK(root,k);
        }else{
            TreeNode parent = findTargetTreeNode(root,target);//获取值为target的节点的父节点
            if(parent != null){
                //判断target是parent的左子节点还是右子节点
                if(parent.left != null && parent.left == target){
                //target是parent的左子节点,那么调用方法获取距离target为k的子节点,然后标记这个节点已经访问过了
                    findDistancdK(parent.left, k);
                    parent.left = null;//标记这个顶点已经访问过了,那么递归distance(root,parent,k - 1)的时候就不会再访问这个节点了
                }else{
                //target是parent的右子节点,调用方法获取距离target为k的子节点,然后标记已经访问过了
                    findDistancdK(parent.right,k);
                    parent.right = null;//标记这个顶点已经访问过了,那么递归distance(root,parent,k - 1)的时候就不会再访问这个节点了
                }
                distanceK(root,parent,k - 1);//递归,获取距离parent为k - 1的节点
            }
        }
        return list;
    }
     //获取target的父节点
    public TreeNode findTargetTreeNode(TreeNode root,TreeNode target){
        if(root == null)//如果root为空,那么将其root返回,表示这棵树没有target这个节点
           return root;
        if(root.left != null && root.left == target)
           return root;
        if(root.right != null && root.right == target)
           return root;
        TreeNode left = findTargetTreeNode(root.left,target);
        if(left != null)//如果能在左子树中找到target的父节点,那么直接将其返回
           return left;
        TreeNode right = findTargetTreeNode(root.right,target);
        if(right != null)//能在右子树中找到target的父节点
           return right;
        return null;
    }
    //获取距离root为k的左右子节点
    public void findDistancdK(TreeNode root,int k){
        if(root != null){
            if(k == 0){
              list.add(root.val);//如果k变成了0,那么将当前的节点添加到列表中,然后返回到上一层递归
              return;
            }
            //如果k不为0,那么就往当前的左右子节点中查找
            findDistancdK(root.left,k - 1);
            findDistancdK(root.right,k - 1);
        }
    }
}

运行结果:
在这里插入图片描述
但是仔细分析下面的代码,发现递归并没有结束递归的条件,程序依旧不会发生报错,这是为什么呢?

public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        if(root == target){
        //当root等于target的时候,在root的左右子树中查找距离root为k的节点,这时候不在进行递归,结束了递归
            findDistancdK(root,k);
        }else{
            TreeNode parent = findTargetTreeNode(root,target);
            if(parent != null){
                if(parent.left != null && parent.left == target){
                    findDistancdK(parent.left, k);
                    parent.left = null;
                }else{
                    findDistancdK(parent.right,k);
                    parent.right = null;
                }
                distanceK(root,parent,k - 1);//递归,获取距离parent为k - 1的节点
            }
        }
        return list;
    }

原因就在于我们每次递归查找距离parent为k - 1的节点,那么它是往上查找的,这时候必然会使得根节点等于target,这时候不会再进入递归了,所以就不需要再多想是否判断k的取值,从而结束递归了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值