LeetCode——二叉树(Java)

二叉树

  • 简介
  • [简单] 144. 二叉树的前序遍历、94. 二叉树的中序遍历、145. 二叉树的后序遍历
  • 二叉树层序遍历
    • [中等] 102. 二叉树的层序遍历
    • [中等] 107. 二叉树的层序遍历 II
    • [中等] 199. 二叉树的右视图
    • [简单] 637. 二叉树的层平均值
    • [中等] 429. N 叉树的层序遍历
    • [中等] 515. 在每个树行中找最大值
    • [中等] 116. 填充每个节点的下一个右侧节点指针、[中等]117. 填充每个节点的下一个右侧节点指针 II
    • [简单] 104. 二叉树的最大深度
    • [简单] 111. 二叉树的最小深度
  • [简单] 226. 翻转二叉树
  • [简单] 101. 对称二叉树
  • [简单] 100. 相同的树
  • [简单] 572. 另一棵树的子树
  • [简单] 222. 完全二叉树的节点个数
  • [简单] 110. 平衡二叉树
  • [简单] 257. 二叉树的所有路径

简介

记录一下自己刷题的历程以及代码。写题过程中参考了 代码随想录的刷题路线。会附上一些个人的思路,如果有错误,可以在评论区提醒一下。
涉及:二叉树前中后序遍历、层序遍历、队列Queue、头插法、递归、ArrayList、LinkedList、递归、StringBuilder

[简单] 144. 二叉树的前序遍历、94. 二叉树的中序遍历、145. 二叉树的后序遍历

144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历

前中后序遍历可以公用一套递归思路,都是比较经典的模板:

//先序遍历
递归访问(){对节点做操作递归访问(左子树)递归访问(右子树)
}//中序遍历
递归访问(){递归访问(左子树)对节点做操作递归访问(右子树)
}//后序遍历
递归访问(){递归访问(左子树)递归访问(右子树)对节点做操作
}
  1. 二叉树的前序遍历
class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> answer = new ArrayList<>();preorder(root, answer);return answer;}public void preorder(TreeNode root, List<Integer> answer){if(root == null) return;answer.add(root.val);preorder(root.left,answer);preorder(root.right,answer);return;}
}
  1. 二叉树的中序遍历
class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> answer = new ArrayList<>();inorder(root, answer);return answer;}public void inorder(TreeNode root, List<Integer> answer){if(root == null) return;inorder(root.left,answer);answer.add(root.val);inorder(root.right,answer);return;}
}
  1. 二叉树的后序遍历
class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> answer = new ArrayList<>();postorder(root, answer);return answer;}public void postorder(TreeNode root, List<Integer> answer){if(root == null) return;postorder(root.left,answer);postorder(root.right,answer);answer.add(root.val);return;}
}

二叉树层序遍历

[中等] 102. 二叉树的层序遍历

原题链接

经典的BFS
用队列保存树节点,每次统计队列的size(),也就是第n层节点数量。
处理这一层的节点,将其子节点全部加入队列,循环往复到队列为空。

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> ans = new ArrayList<List<Integer>>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}ans.add(nums);}return ans;}
}

[中等] 107. 二叉树的层序遍历 II

原题链接

方法①:
与102的最基本的层序遍历相似的逻辑,使用递归的方法把每次ans.add(nums);操作顺序进行了倒序。

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> ans = new ArrayList<List<Integer>>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);recursion(queue, ans);return ans;}public void recursion(Queue<TreeNode> queue, List<List<Integer>> ans){if(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}recursion(queue, ans);ans.add(nums);}return;}
}

方法②:
使用LinkedList,用头插法的方式构造返回值。(LinkedList底层为链表,头插法比较方便,ArrayList底层是连续存储,头插法复杂度为O(n))

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> ans = new LinkedList<>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}ans.add(0, nums);}return ans;}}

[中等] 199. 二叉树的右视图

原题链接

与102的最基本的层序遍历相似的逻辑,构建返回值时每次只把当前层最右边的数加入ans即可。

class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> ans = new ArrayList<Integer>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}ans.add((nums.get(nums.size()-1)));}return ans;}
}

[简单] 637. 二叉树的层平均值

原题链接

class Solution {public List<Double> averageOfLevels(TreeNode root) {Queue<TreeNode> queue = new ArrayDeque<>();List<Double> ans = new ArrayList<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){double num = 0;int k = queue.size();int i = k;while(k-- > 0){TreeNode temp = queue.remove();num += temp.val;if(temp.left != null) queue.add(temp.left);if(temp.right != null) queue.add(temp.right);}ans.add(num / i);}return ans;}
}

[中等] 429. N 叉树的层序遍历

原题链接

class Solution {public List<List<Integer>> levelOrder(Node root) {List<List<Integer>> ans = new ArrayList<List<Integer>>();Queue<Node> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {Node temp = queue.remove();nums.add(temp.val);for(int i = 0; i < temp.children.size(); i++) {queue.add(temp.children.get(i));}}ans.add(nums);}return ans;}
}

[中等] 515. 在每个树行中找最大值

原题链接

class Solution {public List<Integer> largestValues(TreeNode root) {List<Integer> ans = new ArrayList<>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){int max = queue.peek().val;int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();max = max > temp.val ? max : temp.val;if(temp.left != null) queue.add(temp.left);if(temp.right != null) queue.add(temp.right);}ans.add(max);}return ans;}
}

[中等] 116. 填充每个节点的下一个右侧节点指针、[中等]117. 填充每个节点的下一个右侧节点指针 II

[中等] 116. 填充每个节点的下一个右侧节点指针
[中等]117. 填充每个节点的下一个右侧节点指针 II
方法①:
正常的层序遍历,每层除了最后一个节点之外都对next赋值

class Solution {public Node connect(Node root) {List<Integer> ans = new ArrayList<>();Queue<Node> queue = new ArrayDeque<>();if(root == null) return root;queue.add(root);while(!queue.isEmpty()){int k = queue.size();while(k-- > 0) {Node temp = queue.remove();if(k > 0) {temp.next = queue.peek();}if(temp.left != null) queue.add(temp.left);if(temp.right != null) queue.add(temp.right);}}return root;}
}

方法②:
使用next链接来对同层次节点做遍历,可以省去队列的开销
注意Node引用需要申请在方法外,不能做参数传递,java中都是值传递

class Solution {Node last = null, nextStart = null;public Node connect(Node root) {List<Integer> ans = new ArrayList<>();if(root == null) return root;Node p = root;while(p!=null){if(p.left != null){handle(p.left);}if(p.right != null){handle(p.right);}p = p.next;if(p == null && nextStart != null){p = nextStart;nextStart = null;last = null;}}return root;}public void handle(Node p){if(nextStart == null){nextStart = p;}if(last != null){last.next = p;}last = p;}}

[简单] 104. 二叉树的最大深度

原题链接

方法①:层序遍历

class Solution {public int maxDepth(TreeNode root) {int depth = 0;if(root == null) return depth;Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);while(!queue.isEmpty()){depth++;int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}}return depth;}
}

方法②:递归
树的高度就是 其子树的最大高度 + 1,用在多叉树上也是一样的思路

class Solution {public int maxDepth(TreeNode root) {if(root == null) return 0;int leftDepth = maxDepth(root.left);int rightDepth = maxDepth(root.right);return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;}
}

[简单] 111. 二叉树的最小深度

原题链接
方法①:层序遍历找左右子树皆空的点即可

class Solution {public int minDepth(TreeNode root) {int depth = 0;if(root == null) return depth;Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);while(!queue.isEmpty()){depth++;int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();if(temp.left == null && temp.right == null) return depth;if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}}return depth;}
}

方法②:递归求解
用递归求解记住需要的是到叶子节点的深度
如果非叶子节点,假设只有单边左子树,右子数应当是找不到叶子节点也就是距离无穷大,可以设置一个Integer.MAX_VALUE做为返回值,这样通过比较,递归的上一层就会获得左子树找到叶子节点的最小距离 + 1

class Solution {public int minDepth(TreeNode root) {if(root == null) return 0;if(root.left == null && root.right == null) return 1;int leftMin = Integer.MAX_VALUE;int rightMin = Integer.MAX_VALUE;if(root.left != null) leftMin = minDepth(root.left);if(root.right != null) rightMin = minDepth(root.right);return (leftMin < rightMin ? leftMin : rightMin) + 1;}
}

[简单] 226. 翻转二叉树

原题链接

前序遍历的基础上每一次遍历节点做翻转操作。
切记前序、后续、层次遍历都可以,但是不可以是中序遍历,因为中序遍历是左 中 右 的顺序,递归调整左子树之后,处理当前节点会把左右子树对调,这样进入右子数递归时其实还是对原先的左子树做操作。

class Solution {public TreeNode invertTree(TreeNode root) {preorder(root);return root;}public void preorder(TreeNode root){if(root == null) return;TreeNode temp = root.left;root.left = root.right;root.right = temp;preorder(root.left);preorder(root.right);return;}
}

[简单] 101. 对称二叉树

原题链接

经典的递归思路,对左右子树做反方向的递归即可,在左子树上做前序遍历,每次递归left的左节点时就去递归right的右节点,递归left的右节点时则递归right的左节点。

class Solution {public boolean isSymmetric(TreeNode root) {if(root == null) return true;TreeNode left = root.left;TreeNode right = root.right;return recursion(left, right);}public boolean recursion(TreeNode left, TreeNode right){if(left == null && right == null)return true;else if(left != null && right != null) {if (left.val != right.val)return false;if (recursion(left.left, right.right) && recursion(left.right, right.left))return true;}return false;}
}

[简单] 100. 相同的树

原题链接

两棵树同频做前序遍历即可,其他遍历方式也是ok的。

class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {return recursion(p, q);}public boolean recursion(TreeNode p, TreeNode q){if(p == null && q == null)return true;else if(p != null && q != null) {if (p.val != q.val)return false;if (recursion(p.left, q.left) && recursion(p.right, q.right))return true;}return false;}
}

[简单] 572. 另一棵树的子树

原题链接

两层递归
①preorder:对root 的前序遍历,找到与subRoot相同值的节点,作为比较的起点②cmprecursion:对root的节点以及subRoot的根节点 做 同频前序遍历对比

class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(subRoot == null) return true;if(root == null) return true;return preorder(root, subRoot);}public boolean preorder(TreeNode p, TreeNode q){if(p == null) return false;if(p.val == q.val && cmprecursion(p, q))return true;if(preorder(p.left, q) || preorder(p.right, q)) return true;return false;}public boolean cmprecursion(TreeNode p, TreeNode q){if(p == null && q == null) return true;else if(p != null && q != null){if(p.val != q.val) return false;if(cmprecursion(p.left, q.left) && cmprecursion(p.right, q.right))return true;}return false;}
}

[简单] 222. 完全二叉树的节点个数

原题链接

递归

class Solution {public int countNodes(TreeNode root) {if(root == null) return 0;return countNodes(root.left) + countNodes(root.right) + 1;}
}

[简单] 110. 平衡二叉树

原题链接

递归,后序遍历
用-2标记 以当前节点为根节点的子树非平衡二叉树,在递归中一旦出现-2就层层传递到root,用来标识存在子树为非平衡二叉树

class Solution {public boolean isBalanced(TreeNode root) {if(countDepth(root) == -2) return false;return true;}public int countDepth(TreeNode p){if(p == null) return 0;int leftDepth = countDepth(p.left);int rightDepth = countDepth(p.right);int flag = leftDepth - rightDepth;if(leftDepth == -2 || rightDepth == -2 || flag > 1 || flag < -1) return -2;else return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;}
}

[简单] 257. 二叉树的所有路径

原题链接

思路就是DFS深度优先遍历找到每一条路径,效率差异主要体现在对字符串拼接的处理上,使用StringBuilder会更高效一些。
在这里插入图片描述

class Solution {public List<String> binaryTreePaths(TreeNode root) {List<String> ans = new ArrayList<>();if(root == null) return ans;DFS(root, ans, "");return ans;}public void DFS(TreeNode p, List<String> ans, String string){StringBuilder sb = new StringBuilder(string);sb.append(p.val);if(p.left == null && p.right == null){ans.add(sb.toString());return;}sb.append("->");if(p.left != null)DFS(p.left, ans, sb.toString());if(p.right != null)DFS(p.right, ans, sb.toString());}
}

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

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

相关文章

AcWing 4726. 寻找数字

解题思路 在这个二插搜索树中寻找&#xff0c;4和7数量相等&#xff0c;并且大于n的最小数。 相关代码 import java.util.*;public class Main {static String s;static List<Integer> res new ArrayList<>();static long n;static long ansLong.MAX_VALUE;publ…

使用HTML5画布(Canvas)模拟图层(Layers)效果

使用HTML5画布&#xff08;Canvas&#xff09;模拟图层&#xff08;Layers&#xff09;效果 在图形处理和计算机图形学中&#xff0c;图层&#xff08;Layers&#xff09;是指将图像分成不同的可独立编辑、组合和控制的部分的技术或概念。每个图层都可以包含不同的图形元素、效…

18.题目:编号760 数的计算

题目&#xff1a; ###该题主要考察递推、递归 将该题看成若干个子问题 #include<bits/stdc.h> using namespace std; const int N20; int a[N];int dfs(int dep){int res1;for(int i1;i<a[dep-1]/2;i){a[dep]i;resdfs(dep1);}return res; }int main(){int n;cin>…

python并发 map函数的妙用

1.map是什么&#xff1f; map函数是Python中的一个内置函数&#xff0c;用于将一个函数应用到一个或多个可迭代对象的每个元素上&#xff0c;生成一个新的可迭代对象。它的一般形式是&#xff1a; map(function, iterable1, iterable2, ...)其中&#xff0c;function是一个函…

《Spring Security 简易速速上手小册》第8章 常见问题与解决方案(2024 最新版)

文章目录 8.1 异常处理和日志记录8.1.1 基础知识详解8.1.2 重点案例&#xff1a;统一异常处理案例 Demo拓展 8.1.3 拓展案例 1&#xff1a;日志记录策略案例 Demo拓展 8.1.4 拓展案例 2&#xff1a;日志聚合案例 Demo拓展 8.2 多租户安全性问题8.2.1 基础知识详解8.2.2 重点案例…

深入Kafka client

分区分配策略 客户端可以自定义分区分配策略, 当然也需要考虑分区消费之后的offset提交, 是否有冲突。 消费者协调器和组协调器 a. 消费者的不同分区策略, 消费者之间的负载均衡(新消费者加入或者存量消费者退出), 需要broker做必要的协调。 b. Kafka按照消费组管理消费者, …

VUE3:省市区联级选择器

一、实现效果 二、代码展示 <template><div class"page"><select v-model"property.province"><option v-for"item in provinces" :key"item">{{ item }}</option></select><select v-model&…

今日学习总结2024.3.2

最近的学习状态比较好&#xff0c;感觉非常享受知识进入脑子的过程&#xff0c;有点上头。 实验室一个星期唯一一天的假期周六&#xff0c;也就是今天&#xff0c;也完全不想放假出去玩啊&#xff0c;在实验室泡了一天。 很后悔之前胆小&#xff0c;没有提前投简历找实习&…

YOLOv9有效提点|加入MobileViT 、SK 、Double Attention Networks、CoTAttention等几十种注意力机制(五)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

ETH网络中的区块链

回顾BTC网络的区块链系统 什么是区块链&#xff1f;BTC网络是如何运行的&#xff1f;BTC交易模式 - UXTO ETH网络中的区块链 ETH网络的基石依旧是 区块链。上面 什么是区块链&#xff1f; 的文章依旧适用。 相比BTC网络&#xff0c;ETH网络的账户系统就相对复杂&#xff0c;所…

实用工具:实时监控服务器CPU负载状态并邮件通知并启用开机自启

作用&#xff1a;在服务器CPU高负载时发送邮件通知 目录 一、功能代码 二、配置开机自启动该监控脚本 1&#xff0c;配置自启脚本 2&#xff0c;启动 三、功能测试 一、功能代码 功能&#xff1a;在CPU负载超过预设置的90%阈值时就发送邮件通知&#xff01;邮件内容显示…

js中Generator函数详解

定义&#xff1a; promise是为了解决回调地狱的难题出现的&#xff0c;那么 Generator 就是为了解决异步问题而出现的。 普通函数&#xff0c;如果调用它会立即执行完毕&#xff1b;Generator 函数&#xff0c;它可以暂停&#xff0c;不一定马上把函数体中的所有代码执行完毕…

Linux基本指令(下)

目录 1. less指令 2. head与tail指令 3. find指令 示例 4. grep指令 示例 ​编辑 5. zip/unzip 打包与压缩 示例 ​编辑 6. tar指令 7. find指令&#xff1a; -name 8. echo指令 9. 时间相关的指令 1.在显示方面&#xff0c;使用者可以设定欲显示的格式&#xff…

【机器学习】有监督学习算法之:K最近邻

K最近邻 1、引言2、决策树2.1 定义2.2 原理2.3 实现方式2.3.1 距离度量2.3.2 K值的选择 2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 这么长时间没更新了&#xff0c;是不是得抓紧时间了。 小鱼&#xff1a;最近可都是在忙的呢&#xff0c;…

线上历史馆藏系统 Java+SpringBoot+Vue+MySQL

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

day09_商品管理订单管理SpringTaskEcharts

文章目录 1 商品管理1.1 添加功能1.1.1 需求说明1.1.2 核心概念SPUSKU 1.1.3 加载品牌数据CategoryBrandControllerCategoryBrandServiceCategoryBrandMapperCategoryBrandMapper.xml 1.1.4 加载商品单元数据ProductUnitProductUnitControllerProductUnitServiceProductUnitMap…

数据结构与算法-冒泡排序

引言 在数据结构与算法的世界里&#xff0c;冒泡排序作为基础排序算法之一&#xff0c;以其直观易懂的原理和实现方式&#xff0c;为理解更复杂的数据处理逻辑提供了坚实的入门阶梯。尽管在实际应用中由于其效率问题不常被用于大规模数据的排序任务&#xff0c;但它对于每一位初…

【C++】set、multiset与map、multimap的使用

目录 一、关联式容器二、键值对三、树形结构的关联式容器3.1 set3.1.1 模板参数列表3.1.2 构造3.1.3 迭代器3.1.4 容量3.1.5 修改操作 3.2 multiset3.3 map3.3.1 模板参数列表3.3.2 构造3.3.3 迭代器3.3.4 容量3.3.5 修改操作3.3.6 operator[] 3.4 multimap 一、关联式容器 谈…

Hololens 2应用开发系列(1)——使用MRTK在Unity中设置混合现实场景并进行程序模拟

Hololens 2应用开发系列&#xff08;1&#xff09;——使用MRTK在Unity中进行程序模拟 一、前言二、创建和设置MR场景三、MRTK输入模拟的开启 一、前言 在前面的文章中&#xff0c;我介绍了Hololens 2开发环境搭建和项目生成部署等相关内容&#xff0c;使我们能生成一个简单Ho…

matlab 写入格式化文本文件

目录 一、save函数 二、fprintf函数 matlab 写入文本文件可以使用save和fprintf函数 save输出结果: fprintf输出结果: 1.23, 2.34, 3.45 4.56, 5.67, 6.78 7.89, 8.90, 9.01 可以看出fprintf输出结果更加人性化,符合要求,下面分别介绍。 一、save函数 …