代码随想录刷题day42|(二叉树篇)二叉树的最小深度(递归)+完全二叉树结点个数
目录
一、二叉树理论知识
二、最小深度思路
三、完全二叉树求节点思路
四、相关算法题目
五、总结
一、二叉树理论知识
详见:代码随想录刷题day34|(二叉树篇)二叉树的递归遍历-CSDN博客
二、最小深度思路
2.1 递归法
同最大深度,不同点在于,求最小深度时,要单独处理,左子树不为空或者右子树不为空的情况,否则容易出错;(五总结里的错误
2.2 迭代法
详见:代码随想录刷题day38|(二叉树篇)二叉树的层序遍历(429、515、116、117、104、111)-CSDN博客
三、完全二叉树求节点思路
基于完全二叉树的特性:借助满二叉树
满二叉树是一种特殊的二叉树,其中每一层的节点数都达到了可能的最大值。这意味着在满二叉树中,除了叶子节点外,每个节点都有两个子节点。满二叉树的高度为h,那么它的节点总数将是
。
如果一棵树是满二叉树,那么求出深度n后,满二叉树的节点数=
故:首先判断一棵子树是否为满二叉树,如果是,根据深度求出节点数返回给上一层节点,如果不是,继续向下遍历,找出满二叉树(注:单个节点是满二叉树);最后根节点根据左子树数量+右子树数量+1,即为完全二叉树的节点个数;
如何判断是否为满二叉树:在完全二叉树的基础上,从某子树的根节点开始向左遍历的深度 = 向右遍历的深度;即为满二叉树,同时深度也已求出;
四、相关算法题目
111.二叉树的最小深度
class Solution {
public int minDepth(TreeNode root) {
//递归法
return getHight(root);
}
public int getHight(TreeNode node){
if(node == null){
return 0;
}else if(node.left == null && node.right == null){
return 1;
}else if(node.left == null && node.right != null){
return 1 + getHight(node.right);
}else if(node.left != null && node.right == null){
return 1 + getHight(node.left);
}else{
int leftHight = getHight(node.left);
int rightHight = getHight(node.right);
int hight = Math.min(leftHight, rightHight);
return 1 + hight;
}
}
}
222.完全二叉树的节点个数
递归法
class Solution {
public int countNodes(TreeNode root) {
//递归法
return getNum(root);
}
public int getNum(TreeNode node){
if(node == null) return 0;
int leftNum = getNum(node.left);
int rightNum = getNum(node.right);
//getNum(node.left);
//getNum(node.right);
return 1 + leftNum + rightNum;
}
}
迭代法:层序遍历
class Solution {
public int countNodes(TreeNode root) {
//层序遍历 队列统计 按照普通二叉树的求法之迭代法
Deque<TreeNode> deque = new ArrayDeque<>();
if(root == null) return 0;
deque.offer(root);
int count = 0;
while(!deque.isEmpty()){
TreeNode node = deque.poll();
count++;
if(node.left != null) deque.offer(node.left);
if(node.right != null) deque.offer(node.right);
}
return count;
}
}
完全二叉树特性
class Solution {
public int countNodes(TreeNode root) {
//完全二叉树特性
return getNum(root);
}
public int getNum(TreeNode node){
if(node == null) return 0;
TreeNode leftNode = node.left;
TreeNode rightNode = node.right;
int leftDepth = 0;
int rightDepth = 0;
while(leftNode != null){
//遍历左侧的深度
leftNode = leftNode.left;
leftDepth++;
}
while(rightNode != null){
//遍历右侧的深度
rightNode = rightNode.right;
rightDepth++;
}
if(leftDepth == rightDepth){
//说明是满二叉树
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
}else{
int left = getNum(node.left);
int right = getNum(node.right);
return 1 + left + right;
}
}
}
五、总结
1.错误代码:当前代码的逻辑是直接取左右子树的最小深度加 1,但这种逻辑在某些情况下会出错。
class Solution {
public int minDepth(TreeNode root) {
//递归法
return getHight(root);
}
public int getHight(TreeNode node){
if(node == null) return 0;
int leftHight = getHight(node.left);
int rightHight = getHight(node.right);
int hight = Math.min(leftHight, rightHight);
return 1 + hight;
}
}
错误原因:如果某个子树为空,这条路径不应该被考虑。所以应该分情况讨论
2. (2 << leftDepth) - 1
-
2 << leftDepth
是位运算,等价于2 * (2^leftDepth)
,即2^(leftDepth + 1)
。 -
(2 << leftDepth) - 1
就是2^(leftDepth + 1) - 1
,即满二叉树的节点总数。