#例程学习# | java刷题 | 图宽度优先遍历+图广/深度优先遍历_2 | LeetCode863

目录 | java刷题 | 图宽度优先遍历+图广/深度优先遍历--字节DATA面撕题

背景

刷题+总结+进步!
面撕没有写出来,首先想到的是BFS,但是在寻找目标节点的过程中,没想到要如何记录其父节点;在BFS核心代码中判断是否到达末尾的这部分逻辑也没有写完。
总之就是没有撕出来,还是要多刷题,多思考,而不是一开始就去看答案,且题解区很多人没有把思考的那个过程表达清楚(但是人家脑子里是清楚的),对于我这种不是大神的人,看的思路还是入不了门。
下面自己写了一下自己的思考过程,供参考。

实现

分析

图宽度优先遍历+图广度优先遍历
下面为DFS+BFS两种解法。

  • 根据题目,可以看到所要查找的结果中的点集,都是从节点5往外发散,因此直接想到图的BFS。
    其次,换个角度看,也可以认为从5出去的路线一直走到底,当经过k长度的时候,记录节点即可,所以就可以用图的DFS。
  • 第一个点,在于看到这个二叉树的题,要能想到需要构建图。可以从这个角度切入:题目中要找距离节点5为2的点,还向父节点进行了查找,所以查找的方向不是只向下或者层级,所以用二叉树的一般解法不好解。
  • 第二个点,在于BFS时,因为往外扩的时候,扩的是某节点的下一层子节点,所以需要用一个备忘录来记录下一层节点是否之前遍历过,如果不这样的话,当5BFS到父节点3时,3的下一层还会遍历进去5,会造成死循环。备忘录有多重形式,经典题目中是用visited来记录dp数组中对应位置的值是否遍历过,但是此处需要记录的是树节点,没有索引信息,所以想到可以用哈希映射,保存节点以及该节点是否遍历过 的信息。

链接:https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/solution/zi-jie-mian-si-jing-dian-dfsbfs-xu-shou-ptw5g/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

题目

https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/solution/zi-jie-mian-si-jing-dian-dfsbfs-xu-shou-ptw5g/
给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。
返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。

输入: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” 实际上是树上的结点。
上面的输入仅仅是对这些对象进行了序列化描述。

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

题解

思考

1、图深度优先遍历:DFS

直接套模板暴力搜索即可。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

//方法1:DFS
class Solution{
    private Map<TreeNode, TreeNode> parents = new HashMap<>();	//建图,保存当前节点和父节点之间的映射关系
    private Set<TreeNode> visited = new HashSet<>();
    private TreeNode targetNode;	//记录目标节点
    
    public List<Integer> distanceK (TreeNode root, TreeNode target, int k){
        find(root, null, target);
        List<Integer> res = new LinkedList<>();
        dfs(targetNode, res, k);		//深搜目标节点相距k的节点放入Res
        return res;
    }

    private void find(TreeNode root, TreeNode parent, TreeNode target){
        if(root == null)	return;
        if(root.val == target.val){
            targetNode = root;
        }
        parents.put(root, parent);
        find(root.left, root, target);
        find(root.right, root, target);
    }

    private void dfs(TreeNode root, List<Integer> res, int distance){
        if(root == null || visited.contains(root)){
            return;
        }

        //标记为已访问
        visited.add(root);
        if(distance <= 0){          //结束条件判断
            res.add(root.val);	    //已经找到距离最末尾的那个节点了,添加到结果集即可
            return;
        }

        dfs(root.left, res, distance - 1);
        dfs(root.right, res, distance - 1);
        dfs(parents.get(root), res, distance - 1);
        
    }
}

2、图广度优先遍历:队列 BFS

1、利用队列实现;
2、从源节点开始依次按照宽度入队,后弹出
3、每弹出一个节点,将该节点的邻接点中未进入队列的点放入队列;
4、直到队列变空。

//方法2:BFS
class Solution{
    
    private HashMap<TreeNode, TreeNode> map = new HashMap<>();		//key -> 子节点, value -> 对应父节点
    private HashMap<TreeNode, Boolean> visited = new HashMap<>();		//key -> 节点, value -> 之前是否访问过
    private List<Integer> res = new LinkedList<>();	//保存结果
    private TreeNode targetNode;
    
    public List<Integer> distanceK (TreeNode root, TreeNode target, int k){
        if(k == 0){
            res.add(target.val);		//默认寻找的节点一定存在树中
            return res;
        }
        traverse(root, null);		//建立子节点、父节点间的对应关系
        bfs(root, target, k);
        return res;
    }
    
    //深搜树,建立映射关系
    public void traverse(TreeNode node, TreeNode par){
        if(node == null)	return;
        visited.put(node, false);       //这里其实可以用Arrays.fill(visited, false);
        map.put(node, par);
        traverse(node.left, node);
        traverse(node.right, node);
    }
    
    //广搜图,找所有目标节点
    public void bfs(TreeNode root, TreeNode target, int k){
        Queue<TreeNode> q = new LinkedList<>();
        q.add(target);
        visited.put(target, true);

        int step = 0;
        while(!q.isEmpty()){
            step++;
            int sz = q.size();
            for(int i = 0; i < sz; i ++){
                TreeNode temp = q.poll();
                //判断三个方向的节点是否被遍历过,然后依次往外扩
                if(temp.left != null && !visited.get(temp.left)){	//若左子节点没有遍历过
                    if(step == k)	res.add(temp.left.val);
                    q.add(temp.left);
                    visited.put(temp.left, true);
                }
                if(temp.right != null && !visited.get(temp.right)){	//若右子节点没有遍历过
                    if(step == k)	res.add(temp.right.val);
                    q.add(temp.right);
                    visited.put(temp.right, true);
                }
                TreeNode par = map.get(temp);
                if(par != null && !visited.get(par)){	//若父节点没有遍历过
                    if(step == k)	res.add(par.val);
                    q.add(par);
                    visited.put(par, true);
                }
            }
            if(step == k)	break;	//若到达目标距离,则不再广搜了
        }
    }
}

总结

抓紧时间刷题啊!!!

参考

链接: link.
[1]: http://保留格式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值