目录 | 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://保留格式