104.二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
Input: root = [3,9,20,null,null,15,7]
Output: 3
- 什么是二叉树节点的深度?
指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始) - 什么是二叉树节点的高度?
指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始) - 怎么求深度?
前序遍历(中左右) - 怎么求高度?
后序遍历(左右中)
本题根节点的高度就是二叉树的最大深度,因而用后序遍历来计算树的高度。
方法一:递归法,后序遍历
返回条件:空节点
class Solution {
public int maxDepth(TreeNode root) {
// 递归法
return getHeight(root);
}
public int getHeight(TreeNode node) {
if (node == null) {
return 0;
}
int leftHeight = getHeight(node.left);
int rightHeight = getHeight(node.right);
int height = Math.max(leftHeight, rightHeight) + 1;
return height;
}
}
简化
class solution {
public:
int maxDepth(TreeNode* root) {
if (root == null) return 0;
return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
};
方法二:递归法,前序遍历
class Solution {
int result = 0;
public int maxDepth(TreeNode root) {
// 递归法(回溯,直接求深度)
if (root == null) return result;
getDepth(root, 1);
return result;
}
public void getDepth(TreeNode node, int depth) {
// 前序遍历
if (node.left == null && node.right == null) {
result = Math.max(result, depth);
}
if (node.left != null) {
getDepth(node.left, depth+1);
}
if (node.right != null) {
getDepth(node.right, depth+1);
}
}
}
返回条件:叶子节点,前序遍历
class Solution {
int result = 0;
public int maxDepth(TreeNode root) {
if (root == null) return result;
getDepth(root, 0);
return result;
}
public void getDepth(TreeNode node, int depth) {
depth++;
result = result > depth ? result:depth;
if (node.left == null && node.right == null) {// leaf node
return;
}
if (node.left != null) getDepth(node.left, depth);
if (node.right != null) getDepth(node.right, depth);
}
}
有回溯,前序
class Solution {
int result = 0;
public int maxDepth(TreeNode root) {
// 递归法(回溯,直接求深度)
if (root == null) return result;
getDepth(root, 1);
return result;
}
public void getDepth(TreeNode node, int depth) {
result = result > depth ? result:depth; // 中
if (node.left == null && node.right == null) {// leaf node
return;
}
if (node.left != null){ //左
depth++;
getDepth(node.left, depth);
depth--; //回溯
}
if (node.right != null) { //右
depth++;
getDepth(node.right, depth);
depth--; //回溯
}
}
}
方法三:迭代法,层序遍历
class Solution {
public int maxDepth(TreeNode root) {
// 层序遍历
Deque<TreeNode> queue = new LinkedList<>();
int depth = 0;
if (root == null) return 0;
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
depth++; //注意depth增加的位置
while (size -- > 0) {
TreeNode node = queue.poll();
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return depth;
}
}
二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
思路:
- 前序后序遍历都可以,前序求深度,后序求高度
- 求最小深度,求根节点到叶子节点(左右孩子都为空)的最小距离,即求最小高度,对根节点进行后序遍历
- 注意:最小深度是到叶子节点的距离,
- 求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。
递归三步曲:
第一步,确定递归函数的参数和返回值:int getHeight(TreeNode node)
第二步,确定终止条件:遇到空节点
第三步,确定单层递归的逻辑:注意下图的错误
左子树空,右子树+1
右子树空,左子树+1
左右都不空,左右最小+1
方法一:递归法
返回条件:空节点
class Solution {
// 递归法,前序遍历
public int minDepth(TreeNode root) {
return getHeight(root);
}
public int getHeight(TreeNode node) {
if (node == null) return 0;
int leftHeight = getHeight(node.left); // 左
int rightHeight = getHeight(node.right); //右
// 中 处理逻辑
if (node.left == null && node.right != null) {
return 1 + rightHeight;
}
if (node.right == null && node.left != null) {
return 1 + leftHeight;
}
return 1 + Math.min(leftHeight, rightHeight);
}
}
返回条件:叶子节点
class Solution {
public int minDepth(TreeNode root) {
if (root == null) return 0;
return getHeight(root);
}
public int getHeight(TreeNode node) {
if (node.left == null && node.right == null) {
return 1;
}
if (node.left == null && node.right != null)
{// 此时,left为空,即使最小但也不是叶子节点,不符合条件
return 1 + getHeight(node.right);
}
if (node.right == null && node.left != null){
return 1 + getHeight(node.left);
}
return 1 + Math.min(getHeight(node.left), getHeight(node.right));
}
}
简化
class Solution {
public int minDepth(TreeNode root) {
// recurssion
// step2
if (root == null) {
return 0;
}
// step3
if (root.left == null && root.right!=null) {
return 1+ minDepth(root.right);
}
if (root.left !=null && root.right == null) {
return 1+ minDepth(root.left);
}
return 1 + Math.min(minDepth(root.left), minDepth(root.right));
}
}
方法二:递归法,前序遍历
class Solution {
int result = Integer.MAX_VALUE;
public int minDepth(TreeNode root) {
if (root == null) return 0;
getDepth(root, 1);
return result;
}
public void getDepth(TreeNode node, int depth) {
if (node.left == null && node.right == null) {
result = Math.min(result, depth);
return;
} //中
if (node.left != null) {
getDepth(node.left, depth+1);
} //左
if (node.right != null) {
getDepth(node.right, depth+1);
} //右
}
}
方法三:层序遍历
class Solution {
public int minDepth(TreeNode root) {
// iterative
Deque<TreeNode> queue = new LinkedList<>();
if (root == null) {
return 0;
}
queue.offer(root);
int depth = 0;
while (!queue.isEmpty()) {
int size = queue.size(); // will change accoring to offer, so add first
depth++;
while (size -- > 0) { // for one layer
TreeNode node = queue.poll();
if (node.left == null && node.right == null) { // already leaf node
return depth;
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return depth;
}
}
222.完全二叉树的节点个数
普通二叉树
方法一:递归,后序遍历
class Solution {
public int countNodes(TreeNode root) {
// recursive O(n)
if (root == null) return 0;
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
方法二:迭代,层序遍历
class Solution {
public int countNodes(TreeNode root) {
// iterative
Deque<TreeNode> queue = new LinkedList<>();
if (root == null) return 0;
queue.offer(root);
int count = 0;
while (!queue.isEmpty()) {
int size = queue.size();
while (size -- > 0) {
TreeNode node = queue.poll();
count++;
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return count;
}
}
时间复杂度:O(n)
空间复杂度:O(n)
完全二叉树
思路:
完全二叉树的特证?
- 除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
- 若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
完全二叉树的两种可能?
情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
怎么判断是不是满二叉树?
如果递归向左遍历的深度等于递归向右遍历的深度,就是满二叉树。
class Solution {
public int countNodes(TreeNode root) {
// step2: 终止条件,满二叉树,用公式计算节点个数
// 开始根据左深度和右深度是否相同来判断该子树是不是满二叉树
if (root == null) return 0;
TreeNode leftNode = root.left;
TreeNode rightNode = root.right;
int leftDepth = 0; // initialize as 0 for exponential
int rightDepth = 0;
while (leftNode != null) {
leftNode = leftNode.left;
leftDepth++;
}
while (rightNode != null) {
rightNode = rightNode.right;
rightDepth++;
}
if (leftDepth == rightDepth) { // left == right depth, full binary tree
return (2 << leftDepth) - 1;
}
// step3: 单层递归的逻辑
// left right middle 后序遍历
return countNodes(root.left) + countNodes(root.right) + 1; //左右中
}
}
时间复杂度:O(log n × log n)
空间复杂度:O(log n)
补:n叉树的最大深度
题目链接:https://leetcode.com/problems/maximum-depth-of-n-ary-tree/