题目详细:LeetCode.104
递归法很容易理解:
Java解法(递归,深度优先遍历):
class Solution {
private int max = 0;
public int maxDepth(TreeNode root) {
this.dfs(root, 0);
return this.max;
}
public void dfs(TreeNode root, int deep){
if(null == root){
this.max = deep > this.max ? deep : this.max;
return;
}
this.dfs(root.left, deep + 1);
this.dfs(root.right, deep + 1);
}
}
递归法很容易掌握,所以我想尝试用迭代法来解题,但使用前序遍历迭代法来解题好像不是很方便;回到观察问题本身,我发现求二叉树的最大深度,其实就是求叶子节点的最大层数,那么我们也可以利用层序遍历(广度优先遍历)来解题:
Java解法(层序遍历,迭代法,广度优先遍历):
class Solution {
public int maxDepth(TreeNode root) {
return this.bfs(root);
}
public int bfs(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
if(null != root) queue.offer(root);
int deep = 0;
while(!queue.isEmpty()){
deep++;
int len = queue.size();
while(len-- > 0){
TreeNode node = queue.poll();
if(null != node.left) queue.offer(node.left);
if(null != node.right) queue.offer(node.right);
}
}
return deep;
}
}
题目详细:LeetCode.559
这道题和上一题的二叉树的最大深度有异曲同工之妙,区别在于:
所以这道题利用递归法来解决非常简单,跟求解二叉树的最大深度的过程类似,只是这次改为对每一个孩子节点都进行深度优先遍历,最后保留深度最大值。
Java解法(递归,深度优先遍历):
class Solution {
public int maxDepth(Node root) {
return this.dfs(root);
}
public int dfs(Node root){
int deep = 0;
if(null == root) return deep;
for(Node node: root.children){
deep = Math.max(deep, this.dfs(node));
}
return deep + 1;
}
}
题目详细:LeetCode.111
这道题与上面找二叉树的最大深度刚好相反,要求找二叉树的最小深度,但是其解题思路是相似的:
Java解法(递归,深度优先遍历,模拟思路版):
class Solution {
private int min = Integer.MAX_VALUE;
public int minDepth(TreeNode root) {
if(null != root){
this.dfs(root, 1);
return min;
}
return 0;
}
public void dfs(TreeNode root, int deep){
if(null != root && null == root.left && null == root.right){
min = Math.min(min, deep);
return;
}
if(null != root.left) this.dfs(root.left, deep + 1);
if(null != root.right) this.dfs(root.right, deep + 1);
}
}
Java解法(递归,深度优先遍历,精简版):
class Solution {
public int minDepth(TreeNode root) {
return dfs(root);
}
public int dfs(TreeNode root){
if(null == root) return 0;
if(null != root.left && null == root.right)
return 1 + dfs(root.left);
if(null == root.left && null != root.right)
return 1 + dfs(root.right);
return 1 + Math.min(dfs(root.left), dfs(root.right));
}
}
虽然递归法写起来很简单方便,但是经过测试发现,利用递归来解这道题,虽然能够AC,但是速度并不快,为什么呢?
那么也就是说,我们可以按从上到下,从左到右
的顺序来遍历树,假设我们优先在左子树就遍历到了叶子节点得到其深度,那么后面的节点我们都可以不用去关心了,其叶子节点的深度就是二叉树的最小深度,所以优化这道题的关键就在于遍历方式,所以我们可以利用层序遍历来优化这道题:
Java解法(迭代法,层序遍历,广度优先遍历):
class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
return bfs(root);
}
public int bfs(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
if(null != root) queue.offer(root);
int deep = 1;
while(!queue.isEmpty()){
int n = queue.size();
while(n-- > 0){
root = queue.poll();
if(null == root.left && null == root.right) return deep;
if(null != root.left) queue.offer(root.left);
if(null != root.right) queue.offer(root.right);
}
deep++;
}
return deep;
}
}
题目详细:LeetCode.222
这道题如果不涉及完全二叉树,那么我们用任何一种遍历方式来统计二叉树中的节点个数都是可以的,只需要一遍遍历,一边个数 + 1就行了,那么我们可以得到非常大智若愚的递归解法:
Java解法(递归,深度优先遍历,前序遍历):
class Solution {
public int countNodes(TreeNode root) {
if(null == root) return 0;
return 1 + countNodes(root.left) + countNodes(root.right);
}
}
那么这道题又何必是求完全二叉树的节点个数呢,为什么不直接让我求二叉树的节点个数就得了?此时,我注意到题目最下面一段小字:
进阶:遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?
确实,我们如果使用遍历树的方法来统计节点,得到的都是时间复杂度为 O(n) 的算法,完全没有利用到样本数据是一棵完全二叉树的特点,关于完全二叉树的概念和特点详细可以查阅:《代码随想录》— 完全二叉树
在了解了完全二叉树的特点之后,我们不难发现,我们可以利用层序遍历
:
累计之前遍历过的节点数量 + 与空子节点同一层的之前的节点长度
,就可以得到该完全二叉树的节点个数了Java解法(迭代法,广度优先遍历,层序遍历):
class Solution {
public int countNodes(TreeNode root) {
return this.bfs(root);
}
public int bfs(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
if(null != root) queue.offer(root);
int sum = 0;
while(!queue.isEmpty()){
int n = queue.size();
while(n-- > 0){
sum++;
root = queue.poll();
if(null != root.left) queue.offer(root.left);
if(null != root.right) queue.offer(root.right);
if(null == root.left || null == root.right){
return sum + queue.size();
}
}
}
return sum;
}
}
前两天对二叉树的题我都做得很详细,所以基础算是牢固,而且通过昨天的联系,也明白了二叉树的题目无非就是两个要点:选择最合适的遍历方法 + 处理节点的逻辑方法,在今天的练习过后,我更加肯定了这一观点,并且对二叉树不同的遍历方法更加重视了。
题目看似不停的变,其实万变不离其宗,只要遍历方法选对了,剩下的只需要根据题目需求来处理目标节点就可以解题了,对二叉树的遍历越理解,以及不同类型二叉树各自的特点越熟悉,解起二叉树的题来简直就是得心应手,令我感叹道:
读书破万卷,下笔如有神。