LeetCode863:二叉树中所有距离为 K 的结点

LeetCode863:二叉树中所有距离为 K 的结点

题目说明

给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。
返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。
示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2
输出:[7,4,1]
解释:
所求结点为与目标结点(值为 5)距离为 2 的结点,
值分别为 7,4,以及 1

注意,输入的 “root” 和 “target” 实际上是树上的结点。
上面的输入仅仅是对这些对象进行了序列化描述。

分析

人眼很容易看出来,但是要写成逻辑判断的代码就比较复杂了,所以怎么将人思考的过程有逻辑的表达出来也是门功夫。这个题看到确实不会,大概思路就是深度遍历获取距离长度,然后返回相应值,这其实也是最核心的东西。
看了Leetcode上提交的代码,其中有一种方法应用的就是DFS,基本思想是:先求根节点到目标节点上所有节点到目标节点的距离,然后再开始从根节点遍历。
这里从另外一个例子来说明:

假设这里是要求与目标节点2距离为1的所有节点,这里先求各节点的距离,得到:

mp[3]=2
mp[5]=1
mp[2]=0

然后开始从根节点3开始dfs遍历并累加长度,原来路径上的节点到目标节点的长度用上一步得到的数值来表示,也就是2和5之间的距离为1,可以得到节点5。然后2与目标节点距离为0,因此遍历dfs遍历到这里的时候长度变为0,然后再开始从左右孩子遍历得到与目标节点2距离为1的节点7和4。
同理,按照这种方法递推,因为5到2长度为1(mp[5]=1),就可以得到距离目标节点2长度为2的节点3和6。

C++代码

class Solution {
private:
    unordered_map<TreeNode*,int> mp;
public:
    vector<int> distanceK(TreeNode* root, TreeNode* target, int K) {
        vector<int> ans;
        if(root==NULL) return ans;
        findPath(root, target);
        dfs(root,target,K,mp[root],ans);
        return ans;
    }
    //将从root到target的路径上的节点和长度储存在map的键值对中
    int findPath(TreeNode* root, TreeNode* target){
        if(root==NULL) return -1;
        if(root==target){
            mp[root]=0;
            return 0;
        }
        int left=findPath(root->left,target);
        if(left>=0){
            mp[root]=left+1;
            return left+1;
        }
        int right=findPath(root->right,target);
        if(right>=0){
            mp[root]=right+1;
            return right+1;
        }
        return -1;
    }
    
     void dfs(TreeNode *root,TreeNode* target, int K,int length,vector<int> &ans){
        if(root==NULL) return;
        //如果遍历到的节点在根到目标点的路径上,将长度变为map中相应的value
        if(mp.count(root)) length=mp[root];
        if(K==length) ans.push_back(root->val);
        dfs(root->left,target,K,length+1,ans);
        dfs(root->right,target,K,length+1,ans);
    }
};

方法2

这里有用第二种方法,将树转换为图,相连的两个节点之间有边,赋值为1,并定义数组vis表示是否访问过。然后通过对图从目标节点开始深度遍历DFS,到达长度为K值的地方后将节点存入返回的数组中就可以了(注意每个节点的值都不一样),所以初始中心的目标节点只有一个。由于二维数组的遍历比较耗时,unordered_map底层实现更加省时,因此第二种方法执行效率没有第一种高。

参考代码

#define N 500
class Solution {
public:
    int graph[N][N];
    bool vis[N];
    vector<int> res;
    vector<int> distanceK(TreeNode* root, TreeNode* target, int K) {
        treeTograph(root);
        for (int i = 0; i < N; i++)
            vis[i] = false;
        dfs(target->val, 0, K);
        return res;
    }
    void treeTograph(TreeNode* root)
    {
        if (root->left)
        {
            graph[root->val][root->left->val] = 1;
            graph[root->left->val][root->val] = 1;
            treeTograph(root->left);
        }
        if (root->right)
        {
            graph[root->val][root->right->val] = 1;
            graph[root->right->val][root->val] = 1;
            treeTograph(root->right);
        }
    }
    void dfs(int v, int depth, int K)
    {
        vis[v] = true;
        if (depth == K)
        {
            res.push_back(v);
            return;
        }
        for (int i = 0; i < N; i++)
        {
            if (vis[i] == false && graph[v][i] == 1)
            {
                dfs(i, depth + 1, K);
            }
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值