Leetcode刷题笔记 | 二叉树基本性质 | 一天的题量 | 5道题目 | 深度优先搜索 | 广度优先搜索 | 递归 | 遍历

🙋大家好!我是毛毛张!
🌈个人首页: 神马都会亿点点的毛毛张

📌本期毛毛张分享的是LeetCode关于二叉树🌲的性质的一些基础题,做这些题目的本质还是遍历二叉树🏃‍➡️的过程,如果还不熟悉二叉树的遍历方法的同学可以先看看毛毛张的这篇文章➡️LeetCode刷题笔记:二叉树前序遍历、中序遍历、后序遍历和层序遍历 | 递归法 | 迭代法 | 统一迭代法 | 深度优先搜索 | 广度优先搜索

文章目录

  • 1.[110. 平衡二叉树](https://leetcode.cn/problems/balanced-binary-tree/)
    • 1.1 题目描述
    • 1.2 题解
      • 1.2.1 分析
      • 1.2.2 递归:自顶向下
        • 写法1:易于理解
        • 写法2:写法1优化
      • 1.2.3 递归:自底向上
      • 1.2.4 迭代法(不推荐)
  • 2.[222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/)
    • 2.1 题目描述
    • 2.2 题解
      • 2.2.1 递归法
      • 2.2.2 迭代法
  • 3.完全二叉树的判断:[958.二叉树的完全性检验](https://leetcode-cn.com/problems/check-completeness-of-a-binary-tree/)
    • 3.1 题目描述
    • 3.2 题解
      • 3.2.1 深度优先搜索
      • 3.2.2 广度优先搜索
  • 4.[404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/)
    • 4.1 题目描述
    • 4.2 题解
      • 4.2.1 递归法
      • 4.2.2 迭代法
  • 5.[513. 找树左下角的值](https://leetcode.cn/problems/find-bottom-left-tree-value/)
    • 5.1 题目描述
    • 5.2 题解
      • 5.2.1 分析
      • 5.2.2 层序遍历:递归
        • 递归1 毛毛张解法
        • 递归2 (官方题解)
      • 5.2.3 层序遍历:迭代
    • 5.3 练习:[1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/)
      • 5.3.1 题目描述
      • 5.3.2 题解
  • 参考文献

1.110. 平衡二叉树

1.1 题目描述

给定一个二叉树,判断它是否是平衡二叉树
示例 1:
img

输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:

img

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [0, 5000]
  • -104 <= Node.val <= 104

1.2 题解

1.2.1 分析

  • 平衡二叉树定义:二叉树的每个节点的左右子树的高度差的绝对值不超过1,则这颗二叉树是平衡二叉树
  • 根据定义,一棵二叉树是平衡二叉树,当且仅当其所有子树也都是平衡二叉树,因此可以使用递归的方式判断二叉树是不是平衡二叉树,递归的顺序可以是自顶向下或者自底向上。
  • 这里在这里同时介绍两个概念:
    • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
    • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
      image-20240627221128602

1.2.2 递归:自顶向下

  • 对于自顶向下的递归,其单层递归的逻辑如下:
    1️⃣对于当前遍历到的节点,首先计算左右子树的深度,如果左右子树的深度差是否不超过1
    2️⃣再分别递归地遍历左右子节点,并判断左子树和右子树是否平衡
    3️⃣如果上面的条件都满足则以该节点为根节点的二叉树是平衡二叉树
  • 看完这个逻辑之后,我们发现遍历节点的逻辑顺序属于前序遍历,同时还需要编写一个子函数,用来求遍历到的每个节点的深度,因此时间复杂度比较高
  • 整体的逻辑比较容易想到,下面来看看具体的实现代码吧❗
写法1:易于理解
class Solution {//递归 三步走//1.确定形参和返回值public boolean isBalanced(TreeNode root) {//2.确定终止条件if(root == null){return true;}//前序遍历//3.确定单层递归的逻辑//中:左右子树高度差不超过1boolean flagMid = Math.abs(getDepth(root.left) - getDepth(root.right)) <= 1;//左:左子树也需要是平衡二叉树boolean flagLeft = isBalanced(root.left);//右:右子树也需要是平衡二叉树boolean flagRight = isBalanced(root.right);//三个条件都满足才是平衡二叉树return flagMid && flagLeft && flagRight;}//获取树的深度//递归法//1.确定形参和返回值public int getDepth(TreeNode node){//2.确定终止条件if(node == null){return 0;}//3.确定单层递归逻辑return Math.max(getDepth(node.left),getDepth(node.right))  + 1;}
}
写法2:写法1优化

上面的代码,毛毛张为了便于理解,因此每个判断逻辑拆开了,但是这样的运行效率是比较底的,下面对上面的代码进行简化,这种方式的代码运行效率更高

class Solution {//递归法 三步走//1.确定形形参和返回值public boolean isBalanced(TreeNode root) {//2.确定终止条件if(root == null){return true;}//3.确定单层递归逻辑return Math.abs(getDepth(root.left) - getDepth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);}//获取树的深度//递归法 三步走//1.确定形参和返回值public int getDepth(TreeNode node){//2.确定终止条件if(node == null){return 0;}//3.确定单层递归逻辑return Math.max(getDepth(node.left),getDepth(node.right))  + 1;}
}

1.2.3 递归:自底向上

逻辑分析:

  • 自顶向下是先判断整棵树,再判断子树,因此自底向上则是反过来,先从子树判断起,再判断整棵树
  • 自底向上首先需要先遍历整棵树的子树,因此需要使用后序遍历的方式
  • 这个算法的逻辑实现毛毛张都不知道怎么用文字解释出来,最后发现直接图解比较好,直接用动态图来表示更加直观,同时还能帮助大家理解代码的运行逻辑
  • 大家可以先看下面的代码,然后看毛毛张在附上的图解

代码分析:

class Solution {public boolean isBalanced(TreeNode root) {return height(root) >= 0;}//递归法 三步走//1.确定形参和返回值//参数:当前传入节点//返回值:以当前传入节点为根节点的树的高度。public int height(TreeNode root) {//2.确定终止条件//递归的过程中依然是遇到空节点了为终止//返回0,表示当前节点为根节点的树高度为0if (root == null) {return 0;}//3.确定单层递归逻辑//左子树的高度int leftHeight = height(root.left);//右子树的高度int rightHeight = height(root.right);//如果不满足二叉树的条件,可以返回-1来标记已经不符合平衡树的规则if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {return -1;} else {return Math.max(leftHeight, rightHeight) + 1;}}
}

图解:
110

1.2.4 迭代法(不推荐)

  • 大家看下面的代码就知道迭代法比较复杂,所有毛毛张就不是很推荐,但是为了完整性,毛毛张还是把迭代法的代码放在这里
  • 整个代码的就是使用迭代法实现上述自顶向下的代码
class Solution {//迭代法,效率较低,计算高度时会重复遍历//时间复杂度:O(n^2)public boolean isBalanced(TreeNode root) {//判断特殊情况if (root == null) {return true;}//迭代法 借助栈Stack<TreeNode> stack = new Stack<>();TreeNode pre = null;while (root != null || !stack.isEmpty()) {while (root != null) {stack.push(root);root = root.left;}TreeNode inNode = stack.peek();// 右结点为null或已经遍历过if (inNode.right == null || inNode.right == pre) {// 比较左右子树的高度差,输出if (Math.abs(getHeight(inNode.left) - getHeight(inNode.right)) > 1) {return false;}stack.pop();pre = inNode;root = null;// 当前结点下,没有要遍历的结点了} else {root = inNode.right;// 右结点还没遍历,遍历右结点}}return true;}//迭代遍历求二叉树的高度public int getHeight(TreeNode root) {//广度优先遍历(BFS) 迭代法 借助队列//创建队列,存储迭代过程中的节点Queue<TreeNode> queue = new LinkedList<>();//判断特殊情况if(root != null) queue.offer(root);//创建变量,记录迭代的层数,就是树的深度int depth = 0;//开始迭代while(!queue.isEmpty()){//获取每一层的结点数int size = queue.size();//开始迭代每一层for(int i =0;i<size;i++){TreeNode cur = queue.poll();if(cur.left != null) queue.offer(cur.left);if(cur.right != null) queue.offer(cur.right);}//迭代完每一层深度加1depth++;}//迭代完毕,返回结果return depth;}
}

2.222. 完全二叉树的节点个数

2.1 题目描述

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例 1:

img

输入:root = [1,2,3,4,5,6]
输出:6

示例 2:

输入:root = []
输出:0

示例 3:

输入:root = [1]
输出:1

提示:

  • 树中节点的数目范围是[0, 5 * 104]
  • 0 <= Node.val <= 5 * 104
  • 题目数据保证输入的树是 完全二叉树

**进阶:**遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?

2.2 题解

  • 统计二叉树的节点个数,最简单的思路就是遍历二叉树,遍历一个和节点就将计数器+1,遍历二叉树我们熟啊,前序、中序、后序和层序遍历,既有递归实现又有迭代的实现,更多的二叉树的迭代方法可以学习毛毛张的这篇博客➡️LeetCode刷题笔记:二叉树前序遍历、中序遍历、后序遍历和层序遍历 | 递归法 | 迭代法 | 统一迭代法 | 深度优先搜索 | 广度优先搜索

2.2.1 递归法

方法1: 前序遍历

class Solution {//递归法 三步走//遍历的思路:遍历一个节点,节点数量就要加1//创建一个全局变量,记录节点的数量int count = 0;//1.使用题目确定的形参和返回值public int countNodes(TreeNode root) {//2.确定终止条件if(root == null){return 0;}//3.确定单层递归的逻辑//中count++;//左countNodes(root.left);//右countNodes(root.right);return count;}
}

方式2: 后序遍历

class Solution {//递归法 三步走//子问题思路:左右子树的数量统计完了,再加上自身就是一整棵树的节点//1.使用题目确定的形参和返回值public int countNodes(TreeNode root) {//2.确定终止条件if(root == null){return 0;}//3.确定单层递归的逻辑//左子树节点数量int leftNum = countNodes(root.left);//右子树节点数量int rightNum = countNodes(root.right);//加上自身一个节点,返回结果return leftNum + rightNum + 1;}
}

2.2.2 迭代法

class Solution {public int countNodes(TreeNode root) {//迭代法 借助队列//创建队列存储迭代过程中的节点Queue<TreeNode> queue = new LinkedList<>();//判断特殊情况if (root != null) queue.offer(root);//创建计数变量int result = 0;while (!queue.isEmpty()) {//获取每一层的结点数int size = queue.size();//迭代每一层的节点数量while (size -- > 0) {TreeNode cur = queue.poll();result++;if (cur.left != null) queue.offer(cur.left);if (cur.right != null) queue.offer(cur.right);}}return result;}
}

3.完全二叉树的判断:958.二叉树的完全性检验

LeetCode标签:中等

3.1 题目描述

给你一棵二叉树的根节点 root ,请你判断这棵树是否是一棵 完全二叉树

在一棵 完全二叉树 中,除了最后一层外,所有层都被完全填满,并且最后一层中的所有节点都尽可能靠左。最后一层(第 h 层)中可以包含 12h 个节点。

示例 1:

img

输入:root = [1,2,3,4,5,6]
输出:true
解释:最后一层前的每一层都是满的(即,节点值为 {1} 和 {2,3} 的两层),且最后一层中的所有节点({4,5,6})尽可能靠左。

示例 2:

img

输入:root = [1,2,3,4,5,null,7]
输出:false
解释:值为 7 的节点不满足条件「节点尽可能靠左」。

提示:

  • 树中节点数目在范围 [1, 100]
  • 1 <= Node.val <= 1000

3.2 题解

  • 在一棵满二叉树中对二叉树使用层序遍历的顺序从1开始给根节点进行编号,则对于任意一个节点编号为 n n n,它的左孩子编号为 2 ∗ n 2*n 2n,右孩子编号为 2 ∗ n + 1 2*n + 1 2n+1
  • 特征1:因此我们可以通过上述性质在遍历二叉树的时候给遍历的节点的左右孩子进行编号,同时统计每个遍历整颗二叉树的节点数量,遍历完毕之后应该满足如下等式:节点数量 = 最大编号
  • 完全二叉树总的可分为下图这两类:
    image-20240627225932962
  • 特征2:对于一个完全二叉树,层序遍历的过程中遇到第一个空节点之后不应该再出现非空节点

3.2.1 深度优先搜索

  • 这个代码实现依照的是特征1,如果不明白特征1是什么意思的可以看毛毛张下面画的图解,结合着来理解
  • 图解:
    • 符合条件:
      image-20240628090038325
    • 不符合条件:
      image-20240628090551488

代码实现:

class Solution {/*在完全二叉树中,用1表示根节点编号,则对于任意一个节点:n,它的左孩子为:2*n,右孩子为:2*n + 1*///记录编号的最大值int max = 0;//记录节点个数int k = 0;public boolean isCompleteTree(TreeNode root) {traversal(root,1);//最后节点的总数量和编号数量不对应就不是完全二叉树return max == k;}//递归法 三步走//1.确定形参和返回值public void traversal(TreeNode cur,int n) {//2.确定终止条件if(cur == null) return;//3.确定单层递归逻辑//自增变量用于记录节点的数量k = k + 1;//变量n用来表示每个节点的编号//记录编号的最大值max = Math.max(max,n);//如果存在左孩子,那么左孩子的编号一定是2*nif(cur.left != null){traversal(cur.left,2*n);}//如果存在右孩子,那么右孩子的编号一定是2*n + 1if(cur.right != null){traversal(cur.right,2*n+1);}}
}

3.2.2 广度优先搜索

class Solution {//对于一个完全二叉树,层序遍历的过程中遇到第一个空节点之后不应该再出现非空节点//广度优先搜索  层序遍历  借助队列public boolean isCompleteTree(TreeNode root) {//创建队列Queue<TreeNode> queue = new LinkedList<>();//判断特殊情况if(queue != null) queue.offer(root);//设立标志,如果遇到第一个空节点就为trueboolean flag = false;//循环遍历while(!queue.isEmpty()){TreeNode cur = queue.poll();//遇到第一个空节点之后不应该再出现非空节点if(flag == true && cur != null){return false;}//遇到第一个节点,就把标志置为trueif(cur == null){flag = true;continue;}//无论左右节点是否非空,都入队//左queue.offer(cur.left);//右queue.offer(cur.right);}//如果遍历完没有返回不符合,那就是完全二叉树return true;}
}

4.404. 左叶子之和

LeetCode标签:简单

4.1 题目描述

给定二叉树的根节点 root ,返回所有左叶子之和。
示例 1:

img

输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

示例 2:

输入: root = [1]
输出: 0

提示:

  • 节点数在 [1, 1000] 范围内
  • -1000 <= Node.val <= 1000

4.2 题解

  • 这个题目的本质还是遍历,这是在遍历的过程中我们需要判断是否碰到了左叶子节点,因此如何判断是否到了左叶子节点这个逻辑就比较重要
  • 就像我们在区分判断左边还是右边的时候,都有一个参照物,因此,判断左叶子节点的逻辑得通过其父节点才能知道,如果一个节点不为空,节点的左子树不为空,且节点左子树的左子树和右子树均为空才能说明该节点为叶子节点,下面是判断的代码逻辑:
    if(node.left != null && node.left.left == null && node.left.right == null)
    

image-20240628093553532

  • 在前面说过这个题的本质还是遍历二叉树,因此方法的分类也是围绕着遍历二叉树的方法进行分类的,毛毛张在这里分享了两个常见的代码

4.2.1 递归法

class Solution {//递归法 三步走//1.使用题目确定的形参和返回值public int sumOfLeftLeaves(TreeNode root) {//2.确定终止条件if(root == null) return 0;//3.确定单层递归逻辑//定义结果返回变量int sum = 0;//找到左叶子if(root.left != null && root.left.left == null && root.left.right == null){sum += root.left.val;}//左sum += sumOfLeftLeaves(root.left);//右sum += sumOfLeftLeaves(root.right);//返回结果return sum;}
}

4.2.2 迭代法

class Solution {public int sumOfLeftLeaves(TreeNode root) {//迭代法 借助栈 前序遍历//创建结果变量int sum = 0;//创建栈Stack<TreeNode> stack = new Stack<>();//获取当前节点TreeNode cur = root;//开始迭代while(cur != null || !stack.isEmpty()){if(cur != null){//判断是否是左叶子节点if(cur.left != null && cur.left.left == null && cur.left.right == null){sum += cur.left.val;}//中间节点入栈stack.push(cur);cur = cur.left;}else{cur = stack.pop();cur = cur.right;}}//返回结果return sum;}
}

5.513. 找树左下角的值

LeetCode标签:中等

5.1 题目描述

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:

image-20240628093840410

输入: root = [2,1,3]
输出: 1

示例 2:

image-20240628093910533

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7 

提示:

  • 二叉树的节点个数的范围是 [1,104]
  • -231 <= Node.val <= 231 - 1

5.2 题解

5.2.1 分析

  • 这个题不是要求最底层最左边的节点,我们可以首先遍历获取底层的节点,再根据获取的最底层的遍历的节点,获取底层节点列表第一个节点不就是最底层最左边的节点吗?
  • 那么,如何遍历获取最底层的节点呢?我们可以利用层序遍历,层序遍历既可以通过递归实现,也可以通过迭代实现,毛毛张曾在这篇文章介绍过二叉树的层序遍历的各种实现➡️ LeetCode刷题笔记:二叉树前序遍历、中序遍历、后序遍历和层序遍历 | 递归法 | 迭代法 | 统一迭代法 | 深度优先搜索 | 广度优先搜索
  • 下面的方法主要是围绕这两种方法展开,二叉树层序遍历的递归实现其实是一种深度优先遍历(DFS),迭代实现是广度优先搜索(BFS)

5.2.2 层序遍历:递归

递归1 毛毛张解法

分析:

  • 毛毛张在上面的一篇的文章分享了如何实现二叉树的层序遍历的递归实现,如果熟悉的小伙伴可以发现只需要在上面做小小的改动即可,所有毛毛张的下面这种写法来源于二叉树的层序遍历的递归实现
  • 虽然代码的效率可能没有那么高,如果学过二叉树的遍历的小伙伴可以迅速求解出这道题目,不知道大家发现没有,在刷题LeetCode的过程中,最后往往记得是最先使用的方法求解出来的题目,所有毛毛张把这种方法放在第一个就是在不断的强化已经学习过的知识点,如果能用更少的知识点求解更多的题目也是一种能力

代码:

class Solution {//递归  层序遍历//确定递归的形参和返回值//记录每一层的节点值List<List<Integer>> result = new ArrayList<>();public int findBottomLeftValue(TreeNode root) {getLeftNode(root,1);return result.get(result.size()-1).get(0);}public void traversal(TreeNode node,int depth){//确定终止条件if(node == null) return;//确定单层递归的逻辑if(result.size() < depth){//创建列表List<Integer> list = new ArrayList<>();result.add(list);}result.get(depth-1).add(node.val);getLeftNode(node.left,depth+1);getLeftNode(node.right,depth+1);}
}
  • 大家在看了上述代码之后,会不会疑惑这句代码result.get(result.size()-1).get(0),上述代码获取的层序遍历的结果,为啥你能确定遍历的每一层的节点的第一个就是每一层的最左边的结果?

  • 答:因为我在递归的过程中都是左节点优先进入递归,这样就能确保在层序递归遍历的result存储的每一层的节点的第一个节点就是最左边的节点,干说可能比较抽象,大家可以根据代码结合下面的动图理解一下这个问题,左边为递归实现的动态图,右边的层序迭代实现的动态图

DFS 与 BFS 对比

递归2 (官方题解)

分析:

  • 上面的方法省去了分析时间,同时也消耗了比较大的内存,下面我们来进行优化
  • 在上面的代码中,我们会发现,每次要创建新列表的时机是递归的深度又增加了,这里面还隐藏着一个逻辑就是同时递归到每一层的最左边的节点了
    if(result.size() < depth){//创建列表List<Integer> list = new ArrayList<>();result.add(list);
    }
    
  • 分析出上面一个点,列表扩容的时机就说明碰到了每一层的最左边的节点,因此我们可以设置一个变量记录这个节点,递归的过程中不断更新,递归结束自然记录的就是最后一层的最左边的节点,这样就不用去记录每一层的所有结点,大大节省了空间❗

代码:

class Solution {//左下角的值int leftValue = 0;//记录递归过程中树的深度int maxDepth = 0;public int findBottomLeftValue(TreeNode root) {traversal(root,1);return leftValue;}//递归法 三步走//1.确定形参和返回值public void traversal(TreeNode cur,int depth){//2.确定终止条件if(cur == null) return;//3.确定单层递归逻辑//判断深度if(depth > maxDepth){maxDepth = depth;//保证优先左边搜索,然后记录深度最大的叶子节点//递归结束,则记录的结果就是左下角的值leftValue = cur.val;}//左traversal(cur.left,depth+1);//右traversal(cur.right,depth+1);}
}

5.2.3 层序遍历:迭代

分析:

  • 我们首先来看一个迭代过程中的动图:

102二叉树的层序遍历

  • 通过上面的动图我们可以很容易发现,只需要在迭代每一层的时候记录迭代的第一个结点,下面结合上面的图片来理解一下具体的实现吧!

代码:

class Solution {//思路:层序遍历的时候,每次记录遍历的第一个值//当退出循环的之后,记录的就是最底层、最左边的节点的值public int findBottomLeftValue(TreeNode root) {//层序遍历 借助队列Queue<TreeNode> queue = new LinkedList<>();//判断特殊情况if(root != null) queue.offer(root);//每次记录当前层的最左边的节点int result = 0;while(!queue.isEmpty()){//获取当前层的的节点数量int size = queue.size();//开始遍历每一层for(int i =0;i<size;i++){ //获取当前遍历的节点TreeNode cur = queue.poll();//如果是第一个就记录下来if(i==0){result = cur.val;}//左节点入队列if(cur.left!=null) queue.offer(cur.left);//右节点入队if(cur.right!= null) queue.offer(cur.right);}}return result;}
}

5.3 练习:1302. 层数最深叶子节点的和

LeetCode标签:中等

  • 这个题目和上面这个题目的变体,毛毛张在这里就不做详细的介绍,只分享一种比较简单的代码实现,更多的方法,大家根据毛毛张对上面这一题的实现打开LeetCode去尝试一下其它方法

5.3.1 题目描述

给你一棵二叉树的根节点 root ,请你返回 层数最深的叶子节点的和

示例 1:

img

输入:root = [1,2,3,4,5,null,6,7,null,null,null,null,8]
输出:15

示例 2:

输入:root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
输出:19

提示:

  • 树中节点数目在范围 [1, 104] 之间。
  • 1 <= Node.val <= 100

5.3.2 题解

递归:

class Solution {//树的最大深度int maxDepth = -1;//最下层叶子之和int sum = 0;public int deepestLeavesSum(TreeNode root) {traversal(root,1);return sum;}public void traversal(TreeNode cur,int depth){//2.确定终止条件if(cur == null) return;//3.确定单层递归逻辑if(depth > maxDepth){maxDepth = depth;sum = cur.val;}else if(depth == maxDepth){sum += cur.val;}//左traversal(cur.left,depth+1);//右traversal(cur.right,depth+1);}
}

迭代:

class Solution {//层序遍历 递归法//创建二维列表 存储每一行的节点List<List<Integer>> levelNodeList = new ArrayList<>();public int deepestLeavesSum(TreeNode root) {//开始递归获取所有层的节点getLevelNode(root,0);//此时结果所有层的节点已经存储在二维数组levelNodeList中了//只需要获取最后一层的列表List<Integer> list = levelNodeList.get(levelNodeList.size()-1);//然后对改列表里面的值进行求和int sum = 0;for(int i =0;i< list.size();i++){sum += list.get(i);}return sum;}//1.确定形参和返回值public void getLevelNode(TreeNode cur,int depth){//2.确定终止条件if(cur == null) return;//3.确定单层递归逻辑depth++;//树的深度 = 列表的大小if(levelNodeList.size() < depth){List<Integer> list = new ArrayList<>();levelNodeList.add(list);}//把当前节点添加到二维列表中levelNodeList.get(depth-1).add(cur.val);//继续递归getLevelNode(cur.left,depth);getLevelNode(cur.right,depth);}
}

参考文献

  • https://leetcode.cn/
  • https://programmercarl.com/#本站背景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/37526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 中的 Hosts 文件是什么?如何找到并修改它?

什么是 Hosts 文件 Hosts 文件是一个纯文本文件&#xff0c;存在于几乎所有的操作系统中&#xff0c;用于将主机名映射到 IP 地址。在域名系统&#xff08;DNS&#xff09;尚未普及之前&#xff0c;Hosts 文件是计算机网络中唯一用于主机名解析的方式。随着网络规模的扩大和 D…

show-overflow-tooltip 解决elementui el-table标签自动换行的问题

elementui中 el-table中某一行的高度不想因为宽度不够而撑开换行展示的解决方法。可通过show-overflow-tooltip属性解决&#xff0c;如下 代码是这样的 <el-table-column width"80" prop"id" label"ID"></el-table-column> <el…

wsl2收缩虚拟磁盘,减少空间占用

一、说明 由于WSL2使用的是虚拟磁盘&#xff0c;当虚拟磁盘的空间变大时&#xff0c;仅仅删除WSL2文件系统中没有用到的大文件&#xff0c;磁盘空间是无法自动收缩回收的。本文介绍了一种回收WSL2虚拟磁盘空间的方法。 二、停止WSL2 在收缩 WSL2 虚拟磁盘之前&#xff0c;需…

Linux服务器如何测试存储盘性能是否正常?FIO磁盘压测工具的使用详解

针对磁盘的压力性能测试工具有很多&#xff0c;简单的测试可以通过dd命令实现&#xff0c;而比较专业和强大的磁盘IO测试工具&#xff0c;当然首推FIO了。本文将和你们分享FIO工具安装和用法&#xff0c;希望可以帮助到你们~想要了解FIO工具首先你得知道顺序读写和随机读写这两…

编程开发不得不懂的世界协调时UTC的由来

在各种时间标准出现之前&#xff0c;各地都是根据太阳来进行计时的。把太阳连续2次经过地球同一位置所经历的时间间隔称为真太阳日&#xff0c;然后再把这个太阳日划分为更小的时间单位&#xff0c;例如中国古代使用日晷记录时间&#xff0c;把一个太阳日分为12个时辰。因为地球…

FFmpeg教程-三-播放pcm文件-1

目录 一&#xff0c;下载SDL 二&#xff0c;在Qt中测试 1&#xff0c;在pro文件中加入路径 2&#xff0c;在.cpp文件中加入头文件 3&#xff0c;进行测试 4&#xff0c;显示结果 一&#xff0c;下载SDL 通过编程的方式播放音视频&#xff0c;也是需要用到这2个库: FFmpeg…

CICD之Git版本管理及基本应用

CICD:持续集成,持续交付--让对应的资料,对应的项目流程更加规范--提高效率 CICD 有很多的工具 GIT就是其中之一 1.版本控制概念与环境搭建 GIT的概念: Git是一款分布式源代码管理工具(版本控制工具) ,一个协同的工具。 Git得其数据更像是一系列微型文件系统的快照。使用Git&am…

一年前 LLM AGI 碎片化思考与回顾系列⑧ · 穿越SystemⅡ未知之境

阅读提示&#xff1a; 本篇系列内容的是建立于自己过去一年在以LLM为代表的AIGC快速发展浪潮中结合学术界与产业界创新与进展的一些碎片化思考并记录最终沉淀完成&#xff0c;在内容上&#xff0c;与不久前刚刚完稿的那篇10万字文章 「融合RL与LLM思想&#xff0c;探寻世界模型…

智慧校园-教材管理系统总体概述

智慧校园教材管理系统&#xff0c;作为教育信息化进程的又一实践成果&#xff0c;正逐步改变着传统教材管理的模式。该系统通过集成先进的信息技术&#xff0c;对教材从采购、分配、使用到回收的全过程进行了全面的数字化改造&#xff0c;旨在构建一个高效、透明、节约的教材管…

一次可输入多张图像,还能多轮对话!最新开源数据集,让AI聊天更接近现实

大模型对话能更接近现实了&#xff01; 不仅可以最多输入20张图像&#xff0c;还能支持多达27轮对话。可处理文本图像tokens最多18k。 这就是最新开源的超长多图多轮对话理解数据集MMDU&#xff08;Multi-Turn Multi-Image Dialog Understanding&#xff09;。 大型视觉语言模…

2025艺考时间线来啦!所有艺考生码住!

2025届艺考生们的征途即将启程。对于每一个即将参加艺考的考生和家长来说&#xff0c;梳理艺考时间节点是尤为重要的。 对于艺考生而言&#xff0c;更早的规划意味着更充分的准备时间&#xff0c;更扎实的专业能力。补齐艺考信息差&#xff0c;以下2025艺考时间线一定要看明白…

知识库在AI大模型中的使用流程

大模型知识库的使用流程通常包括以下关键步骤&#xff0c;大模型知识库的使用流程需要跨学科的知识和技能&#xff0c;包括自然语言处理、数据库管理、软件工程等。同时&#xff0c;也需要关注用户体验、性能优化、安全保护等方面&#xff0c;以提供高质量的知识服务。北京木奇…

CC7关于ConstantTransformer返回值不能和put一样的分析

CC7关于ConstantTransformer返回值不能和put一样的分析 前言 实验室的gaorenyusi也是学到cc7的时候问了我一个很好的问题&#xff0c;我当时学的时候没有在意&#xff0c;然后就去调试分析解决了一下 分析 首先是paylaod package CC7;import org.apache.commons.collectio…

三英战吕布 | 第5集 | 温酒斩华雄 | 竖子不足与谋 | 三国演义 | 逐鹿群雄

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f4cc;这篇博客分享的是《三国演义》文学剧本第Ⅰ部分《群雄逐鹿》的第5️⃣集《三英战吕布》的经典语句和文学剧本全集台词 文章目录 1.经典语句2.文学剧本台…

MySQL之如何定位慢查询

1、如何定位慢查询 1.1、使用开源工具 调试工具&#xff1a;Arthas 运维工具&#xff1a;Promethuss、Skywalking 1.2、MySQL自带慢日志 慢查询日志记录了所有执行时间超过指定参数&#xff08;long_query_time&#xff0c;单位&#xff1a;秒&#xff0c;默认10秒&#x…

小白上手AIGC-基于PAI-DSW部署Stable Diffusion文生图Lora模型

小白上手AIGC-基于PAI-DSW部署Stable Diffusion文生图Lora模型 前言资源准备开启体验服务创建工作空间 部署服务创建DSW实例安装Diffusers启动WebUI 写在最后 前言 在上一篇博文小白上手AIGC-基于FC部署stable-diffusion 中&#xff0c;说到基于函数计算应用模板部署AIGC文生图…

python基础语法 004-1流程控制- 条件控制

1 条件控制 1.1 表达 条件表达式冒号缩进 1.1.1 单个条件&#xff1a;满足表达式 """ ############if的表示 if 条件表达式:(缩进)条件满足以后要运行的代码例子: #遇到冒号要缩进 #缩进&#xff1a;1个缩进用4个空格&#xff0c;整个篇幅缩进需要统一 #4个…

揭开统计分析的秘密:独立样本和配对样本T检验实战案例

一、独立样本T检验 1.收集20名学生的自信心值 见下表&#xff0c;试问该指标是否与性别有关&#xff1f;&#xff08;非参数检验或参数检验&#xff09; 数据值 性别 1&#xff0c;1&#xff0c;1&#xff0c;1&#xff0c;2&#xff0c;2&#xff0c;1&#xff0c;1&#…

国产操作系统上netstat命令详解 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统上netstat命令详解 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上使用netstat命令的详解文章。netstat是网络统计&#xff08;network statistics&#xff09;的缩写&#xff0c;它是一…

【股指期权投教】一手股指期权大概多少钱?

一手股指期权的权利金大概在几千人民币左右&#xff0c;如果是作为期权卖方还需要另外缴纳保证金的。国内的股指期权有三种&#xff0c;沪深300、上证50、中证1000股指期权&#xff0c;每点合约人民币100 元。 期权合约的价值计算可以通过此公式得出&#xff1a;权利金的支付或…