二叉树DFS与BFS的问题整理
来源:互联网 发布:霍格沃茨校服淘宝 编辑:程序博客网 时间:2024/05/10 11:26
二叉树DFS与BFS的问题整理
摘要
在上一篇文章中介绍了深度优先(DFS)和广度优先(BFS)搜索,本篇整理了一些利用DFS和BFS解决的一些问题。会不断更新新的问题。
问题
1. Spiral/Zigzag Level Order traversal:
参考自:http://www.java2blog.com/2014/08/spiralzigzag-level-order-traversal-of.html
代码实现以S形遍历一个二叉树,效果如下图:
思路:看到这个图会联想到BFS,只是BFS中每层都以从左到右的顺序遍历,而此图每层会改变一次方向。所以我们需要1.一个判断本层该向左还是向右遍历的标识变量;2.根据表示变量,按一定顺序保存每行各个元素的容器。然后问题是怎样每向下一层就改变一次表示变量。
方法是利用两个Stack数据结构,其中一个为临时Stack每向下遍历一层就重新创建并且按规定顺序保存下一层的节点;另一个用来处理上一个临时Stack保存下来的数据,并且每处理完一个临时Stack就改变一次表示变量。代码如下:
public static void spiralOrZigzagLevelOrder(TreeNode root) { if(root==null) return; Stack<TreeNode> stack=new Stack<TreeNode>(); //办事Stack stack.push(root); boolean directionflag=false; //记录方向的表示变量 while(!stack.isEmpty()) { Stack<TreeNode> tempStack=new Stack<TreeNode>(); //临时Stack while(!stack.isEmpty()) //此循环内都是同一层节点操作 { TreeNode tempNode=stack.pop(); //弹出并打印一个节点 System.out.printf("%d ",tempNode.data); if(!directionflag) //flag初始为false,第一次存下一层(第二层)节点时以从右到左为顺序 //所以存入Stack时先存左再=后存右(后进先出) { if(tempNode.left!=null) tempStack.push(tempNode.left); if(tempNode.right!=null) tempStack.push(tempNode.right); }else { if(tempNode.right!=null) tempStack.push(tempNode.right); if(tempNode.left!=null) tempStack.push(tempNode.left); } } //此时一层节点处理完毕 directionflag=!directionflag; //改变方向 stack=tempStack; //将存好下一层节点的临时Stack交给办事Stack } }
2. Path Sum:
给一个二叉树和一个int sum,判断是否有一个从根节点到末端节点的路径,使得路径从头到尾所有节点的值相加等于sum。
例如如下的二叉树,和sum = 21,
我们发现8-5-7-1这条路径四个节点相加为21 所以返回true。
思路:从根节点到末端节点很容易想到深度优先。如果考虑创建一个新的int累加路径上的节点值,然后对比sum,那么问题会变得很复杂,因为一条路径不行需要减去节点值重新累加。所以方法是从sum中减去节点值,使用迭代,预先判断路径末端节点是否符合要求,代码如下。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */public class Solution { public boolean hasPathSum(TreeNode root, int sum) { if(root==null) return false; if(root.left==null && root.right==null) return sum==root.val; return (hasPathSum(root.left, sum-root.val) || hasPathSum(root.right, sum-root.val)); }}
3. Minimum Depth of Binary Tree:
给一个二叉树,求出其中的最短路径。
思路:求最短的路径,第一想法是只要从上至下遍历出每个路径的长度,返回最短的即可。答案与此思路也类似,广度优先和深度优先都可以解决此题。
广度优先:
public int minDepth(TreeNode root) { if(root==null) return 0; //1 else if(root.left!=null && root.right !=null) return 1 + Math.min(minDepth(root.left), minDepth(root.right)); //2 else return 1 + minDepth(root.left) + minDepth(root.right); //3 //最后一行中minDepth(root.left)和minDepth(root.right)至少一个为0}
广度优先的代码看似复杂,其实原理很简单,从根节点开始向下访问,每个访问的节点有三种可能的情况:
–若访问节点左右子都存在(运行//2),取左右子中包含的更短路径并+1,+1是因为它有子节点;
–若访问的节点左右子至少有一个不存在(运行//3),路径+1并且继续访问其子节点(因为它有子,所以肯定不在末端);
–若访问节点为空,返回0,因为它不占长度。
叙述起来比较拗口,画一个简单地二叉树,对照代码很容易想清楚。
深度优先:
int min = Integer.MAX_VALUE; //初始化一个intpublic int minDepth(TreeNode root) { if (root ==null){ return 0; } dfs(root,1); //此时根节点非空,最小长度至少为1,带入计算 return min;}public void dfs(TreeNode node, int height){ if (node.left!=null ) { //左子非空,带入左子且长度+1 dfs(node.left, height + 1); } if(node.right !=null){ //右子同理 dfs(node.right,height+1); } if (node.left == null && node.right==null){ //此时访问到末端节点,若得出的长度比当前min小,赋给min min = Math.min(min,height); }}
4. Binary Tree Paths
给一个二叉树,将其从根到末梢的所有路径保存到List里。例如二叉树[1,2,3],返回List形式为{“1->2”,”1->3”}。
思路:路径问题很容易联想到深度优先。于是我们继续分析:1. 对于每个路径我们需要一个String保存从根到末梢的所有点,也就是说每个路径就是一个String,我们可以到末梢点的时候(左右子都为空)将它存进List;2. 对于最后一个末梢点,它后面没有”->”字符,所以也要特殊处理;3. 用String直接相加会占用很大内存,所以考虑使用StringBuilder。
public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); StringBuilder path = new StringBuilder(); helper(root,path,res); return res; } public void helper(TreeNode root, StringBuilder path, List<String> res){ if(root==null) return; int len = path.length(); //记录添加此节点前的字符长度 path.append(root.val); if(root.left==null && root.right==null){ res.add(path.toString()); } else{ path.append("->"); helper(root.left,path,res); //1 helper(root.right,path,res); //2 } path.setLength(len); //此行意义在于运行//1之后遇到末梢节点,此时继续运行//2的话, //path中已被添加了刚刚的末梢节点,所以再添加末梢节点后, //截掉该末梢节点,继续运行//2 //否则会生成"1->23"这样的结果 }
5. Sum of Left Leaves
求出一个二叉树中,左子叶之和。
思路:此题比较简单,可用遍历和迭代两种方法解决。首先是迭代方法:对于每个节点,先判断其左子是否为叶,若为叶则加入结果,若不为叶,以及右子,都放入迭代。遍历方法:同样对于每个节点,先判断其左子是否为叶,若为叶则加入结果,若不为叶,加入
- 二叉树DFS与BFS的问题整理
- 二叉树的DFS/BFS
- 二叉树的DFS和BFS
- 二叉树的深度优先遍历(DFS)与广度优先遍历(BFS)
- 搜索问题:DFS 与 BFS
- BFS、DFS与选课问题
- 【转载】八数码问题BFS与DFS的比较
- BFS与DFS的区别
- 图的BFS与DFS
- DFS与BFS的总结
- DFS与BFS的总结
- DFS与BFS的总结
- DFS与BFS 的区别
- 二叉树类和DFS,BFS
- 用二叉树区分DFS和BFS
- 二叉树中的DFS和BFS
- 二叉树的建立与DFS遍历
- 【POJ】3984 迷宫问题 BFS 与 DFS
- MySQL日期时间函数大全
- Java中FileInputStream读写数据时换行处理
- oracle 全文检索
- java网络编程客户端,服务器端
- hibernate中的SessionFactory的openSession与getCurrentSession
- 二叉树DFS与BFS的问题整理
- 弹簧动画效果
- PHP基础整理3
- 为android自定义控件添加自定义属性
- 分布式锁-redis实现(2)
- ${pageContext.request.contextPath} JSP取得绝对路径
- 设置动画的自动反转
- 获取当前按钮旋转的角度
- Kafka分布式安装及验证测试