递归三部曲!!!
- 确定递归函数的参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
模板题
java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//1 确定递归函数和返回值
public TreeNode invertTree(TreeNode root) {
//2 确定终止条件
if(root == null){
return null;
}
//3 确定单层递归逻辑 交换左右孩子
swap(root);
invertTree(root.left);
invertTree(root.right);
return root;
}
//交换函数
void swap(TreeNode root){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
模板
递归模板
前序遍历
java
import java.util.List;
import java.util.ArrayList;
/**
* 定义二叉树节点类
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决问题的类
*/
class Solution {
/**
* 用于存储前序遍历的结果
*/
List<Integer> ret = new ArrayList<>();
/**
* 前序遍历二叉树,并返回遍历的结果
* @param root 二叉树的根节点
* @return 返回前序遍历的节点值列表
*/
public List<Integer> preorderTraversal(TreeNode root) {
Demo(root); // 调用递归方法进行前序遍历
return ret; // 返回遍历结果
}
/**
* 递归方法进行前序遍历
* @param root 当前遍历到的节点
*/
void Demo(TreeNode root){
if(root == null){ // 如果当前节点为空,返回
return;
}
ret.add(root.val); // 将当前节点的值添加到结果列表中
Demo(root.left); // 递归遍历左子树
Demo(root.right); // 递归遍历右子树
}
}
后序遍历
java
import java.util.List;
import java.util.ArrayList;
/**
* 定义二叉树节点类
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 默认构造函数
TreeNode() {}
// 带一个参数的构造函数,初始化节点值
TreeNode(int val) { this.val = val; }
// 带三个参数的构造函数,初始化节点值和左右子节点
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决问题的类
*/
class Solution {
/**
* 用于存储后序遍历的结果
*/
List<Integer> ret = new ArrayList<>();
/**
* 后序遍历二叉树,并返回遍历的结果
* @param root 二叉树的根节点
* @return 返回后序遍历的节点值列表
*/
public List<Integer> postorderTraversal(TreeNode root) {
Demo(root); // 调用递归方法进行后序遍历
return ret; // 返回遍历结果
}
/**
* 递归方法进行后序遍历
* @param root 当前遍历到的节点
*/
void Demo(TreeNode root){
if(root == null){ // 如果当前节点为空,返回
return;
}
Demo(root.left); // 递归遍历左子树
Demo(root.right); // 递归遍历右子树
ret.add(root.val); // 将当前节点的值添加到结果列表中
}
}
中序遍历
java
import java.util.List;
import java.util.ArrayList;
/**
* 定义二叉树节点类
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 默认构造函数
TreeNode() {}
// 带一个参数的构造函数,初始化节点值
TreeNode(int val) { this.val = val; }
// 带三个参数的构造函数,初始化节点值和左右子节点
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决问题的类
*/
class Solution {
/**
* 用于存储中序遍历的结果
*/
List<Integer> ret = new ArrayList<>();
/**
* 中序遍历二叉树,并返回遍历的结果
* @param root 二叉树的根节点
* @return 返回中序遍历的节点值列表
*/
public List<Integer> inorderTraversal(TreeNode root) {
Demo(root); // 调用递归方法进行中序遍历
return ret; // 返回遍历结果
}
/**
* 递归方法进行中序遍历
* @param root 当前遍历到的节点
*/
void Demo(TreeNode root){
if(root == null){ // 如果当前节点为空,返回
return;
}
Demo(root.left); // 递归遍历左子树
ret.add(root.val); // 将当前节点的值添加到结果列表中
Demo(root.right); // 递归遍历右子树
}
}
迭代版本
前序遍历
java
import java.util.List;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 定义二叉树节点类
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 默认构造函数
TreeNode() {}
// 带一个参数的构造函数,初始化节点值
TreeNode(int val) { this.val = val; }
// 带三个参数的构造函数,初始化节点值和左右子节点
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 前序遍历二叉树,并返回遍历的结果
* @param root 二叉树的根节点
* @return 返回前序遍历的节点值列表
*/
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>(); // 创建一个列表用于存储遍历结果
if(root == null){ // 如果根节点为空,则直接返回空列表
return ret;
}
Deque<TreeNode> deque = new ArrayDeque<>(); // 创建一个双端队列用于存储待访问的节点
deque.addFirst(root); // 将根节点添加到队列的前端
while(!deque.isEmpty()){ // 当队列不为空时,进行循环
TreeNode node = deque.removeFirst(); // 从队列前端移除一个节点
ret.add(node.val); // 将节点的值添加到结果列表中
// 如果节点的右子节点不为空,则将其添加到队列的前端
if(node.right != null){
deque.addFirst(node.right);
}
// 如果节点的左子节点不为空,则将其添加到队列的前端
if(node.left != null){
deque.addFirst(node.left);
}
}
return ret; // 返回遍历结果
}
}
后序遍历
java
import java.util.List;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Collections;
/**
* 定义二叉树节点类
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 默认构造函数
TreeNode() {}
// 带一个参数的构造函数,初始化节点值
TreeNode(int val) { this.val = val; }
// 带三个参数的构造函数,初始化节点值和左右子节点
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 后序遍历二叉树,并返回遍历的结果
* @param root 二叉树的根节点
* @return 返回后序遍历的节点值列表
*/
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>(); // 创建一个列表用于存储遍历结果
if(root == null){ // 如果根节点为空,则直接返回空列表
return ret;
}
Deque<TreeNode> deque = new ArrayDeque<>(); // 创建一个双端队列用于存储待访问的节点
deque.add(root); // 将根节点添加到队列的后端
while(!deque.isEmpty()){ // 当队列不为空时,进行循环
TreeNode node = deque.removeFirst(); // 从队列后端移除一个节点
ret.add(node.val); // 将节点的值添加到结果列表中
// 如果节点的左子节点不为空,则将其添加到队列的前端
if(node.left != null){
deque.addFirst(node.left);
}
// 如果节点的右子节点不为空,则将其添加到队列的前端
if(node.right != null){
deque.addFirst(node.right);
}
}
// 后序遍历的结果是左-右-根,而我们添加到列表的顺序是根-左-右,所以需要反转列表
Collections.reverse(ret);
return ret; // 返回遍历结果
}
}
中序遍历
java
import java.util.List;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 定义二叉树节点类
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 默认构造函数
TreeNode() {}
// 带一个参数的构造函数,初始化节点值
TreeNode(int val) { this.val = val; }
// 带三个参数的构造函数,初始化节点值和左右子节点
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 中序遍历二叉树,并返回遍历的结果
* @param root 二叉树的根节点
* @return 返回中序遍历的节点值列表
*/
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>(); // 创建一个列表用于存储遍历结果
if(root == null){ // 如果根节点为空,则直接返回空列表
return ret;
}
Deque<TreeNode> deque = new ArrayDeque<>(); // 创建一个双端队列用于存储待访问的节点
TreeNode cur = root; // 初始化当前节点为根节点
// 使用循环进行遍历,直到当前节点为空且队列为空
while(cur != null || !deque.isEmpty()){
// 如果当前节点不为空,则将当前节点及其所有左子节点加入队列
if(cur != null){
deque.addFirst(cur); // 将当前节点加入队列前端
cur = cur.left; // 移动到当前节点的左子节点
}else{
// 如果当前节点为空,则从队列中取出一个节点
cur = deque.removeFirst(); // 从队列前端移除一个节点
ret.add(cur.val); // 将节点的值添加到结果列表中
cur = cur.right; // 移动到当前节点的右子节点
}
}
return ret; // 返回遍历结果
}
}
层序遍历
java
import java.util.ArrayList;
import java.util.List;
import java.util.ArrayDeque;
/**
* 定义一个二叉树的节点
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 指向左子节点的引用
TreeNode right; // 指向右子节点的引用
// 构造函数
TreeNode() {}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决方案类,包含 levelOrder 方法来遍历二叉树
*/
class Solution {
/**
* 该方法执行二叉树的层序遍历(广度优先搜索)。
*
* @param root 要遍历的二叉树的根节点
* @return 一个列表的列表,其中每个子列表包含特定层级的节点值
*/
public List<List<Integer>> levelOrder(TreeNode root) {
// 初始化一个空列表来存储结果
List<List<Integer>> ret = new ArrayList<>();
// 如果根节点为空,返回一个空列表,因为没有节点可以遍历
if (root == null) {
return ret;
}
// 创建一个双端队列来保存每一层的节点
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
// 将根节点添加到双端队列中
deque.addFirst(root);
// 继续遍历直到双端队列为空
while (!deque.isEmpty()) {
// 创建一个列表来存储当前层级的节点值
ArrayList<Integer> list = new ArrayList<>();
// 遍历当前层级的节点
for (int i = deque.size(); i > 0; i--) {
// 从双端队列中移除最后一个节点(因为我们是从右到左处理)
TreeNode cur = deque.removeLast();
// 将当前节点的值添加到列表中
list.add(cur.val);
// 如果当前节点有左子节点,将其添加到双端队列的前端
if (cur.left != null) {
deque.addFirst(cur.left);
}
// 如果当前节点有右子节点,将其添加到双端队列的前端
if (cur.right != null) {
deque.addFirst(cur.right);
}
}
// 将当前层级的值列表添加到结果列表中
ret.add(list);
}
// 返回包含每层节点值的结果列表
return ret;
}
}
层序遍历相关题目
二叉树的右视图
java
import java.util.ArrayList;
import java.util.List;
import java.util.ArrayDeque;
/**
* 定义一个二叉树的节点
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 指向左子节点的引用
TreeNode right; // 指向右子节点的引用
// 构造函数
TreeNode() {}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决方案类,包含 rightSideView 方法来获取二叉树右侧视图
*/
class Solution {
/**
* 该方法获取二叉树的右侧视图。
*
* @param root 要获取右侧视图的二叉树的根节点
* @return 一个列表,包含从根节点到每一层最右边的节点值
*/
public List<Integer> rightSideView(TreeNode root) {
// 初始化一个空列表来存储结果
List<Integer> ret = new ArrayList<>();
// 如果根节点为空,返回空列表
if (root == null) {
return ret;
}
// 创建一个双端队列来保存每一层的节点
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
// 将根节点添加到双端队列的前端
deque.addFirst(root);
// 当双端队列不为空时,继续遍历
while (!deque.isEmpty()) {
// 获取当前层的节点数量
int levelSize = deque.size();
// 用于记录当前层是否已经处理到最后一个节点
int count = 0;
// 遍历当前层的所有节点
for (int i = 0; i < levelSize; i++) {
// 从双端队列的前端移除节点
TreeNode cur = deque.removeFirst();
// 每处理完一层的最后一个节点,就将其值添加到结果列表中
if (i == levelSize - 1) {
ret.add(cur.val);
}
// 如果当前节点有左子节点,将其添加到双端队列的前端
if (cur.left != null) {
deque.addLast(cur.left);
}
// 如果当前节点有右子节点,将其添加到双端队列的前端
if (cur.right != null) {
deque.addLast(cur.right);
}
// 每处理一个节点,计数器加一
count++;
}
}
// 返回包含每层最右边节点值的结果列表
return ret;
}
}
二叉树的层平均值
java
import java.util.ArrayList;
import java.util.List;
import java.util.Deque;
import java.util.ArrayDeque;
/**
* 定义一个二叉树的节点
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 指向左子节点的引用
TreeNode right; // 指向右子节点的引用
// 构造函数
TreeNode() {}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决方案类,包含 averageOfLevels 方法来计算二叉树每一层的平均值
*/
class Solution {
/**
* 该方法计算二叉树每一层的平均值。
*
* @param root 要计算每层平均值的二叉树的根节点
* @return 一个列表,包含每一层的平均值
*/
public List<Double> averageOfLevels(TreeNode root) {
// 初始化一个空列表来存储每层的平均值
List<Double> ret = new ArrayList<>();
// 如果根节点为空,返回空列表
if (root == null) {
return ret;
}
// 创建一个双端队列来保存每一层的节点
Deque<TreeNode> arrayDeque = new ArrayDeque<>();
// 将根节点添加到双端队列的前端
arrayDeque.addFirst(root);
// 当双端队列不为空时,继续遍历
while (!arrayDeque.isEmpty()) {
// 初始化当前层的节点值总和
double sum = 0.0;
// 获取当前层的节点数量
int m = arrayDeque.size();
// 遍历当前层的所有节点
for (int i = arrayDeque.size(); i > 0; i--) {
// 从双端队列的后端移除节点
TreeNode cur = arrayDeque.removeLast();
// 将当前节点的值累加到总和中
sum += cur.val;
// 如果当前节点有左子节点,将其添加到双端队列的前端
if (cur.left != null) {
arrayDeque.addFirst(cur.left);
}
// 如果当前节点有右子节点,将其添加到双端队列的前端
if (cur.right != null) {
arrayDeque.addFirst(cur.right);
}
}
// 将当前层的平均值添加到结果列表中
ret.add(sum / m);
}
// 返回包含每层平均值的结果列表
return ret;
}
}
N叉树的层序遍历
java
import java.util.ArrayList;
import java.util.List;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 定义一个树节点
*/
class Node {
public int val; // 节点的值
public List<Node> children; // 子节点列表
// 构造函数
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
}
/**
* 解决方案类,包含 levelOrder 方法来对树进行层序遍历
*/
class Solution {
/**
* 该方法对树进行层序遍历,并返回每一层的节点值。
*
* @param root 树的根节点
* @return 一个列表的列表,其中每个子列表包含每一层的节点值
*/
public List<List<Integer>> levelOrder(Node root) {
// 初始化一个空列表来存储层序遍历的结果
List<List<Integer>> ret = new ArrayList<>();
// 如果根节点为空,返回空列表
if (root == null) {
return ret;
}
// 创建一个双端队列来存储每一层的节点
Deque<Node> deque = new ArrayDeque<>();
// 将根节点添加到双端队列的前端
deque.addFirst(root);
// 当双端队列不为空时,继续遍历
while (!deque.isEmpty()) {
// 创建一个列表来存储当前层的节点值
ArrayList<Integer> list = new ArrayList<>();
// 获取当前层的节点数量
for (int i = deque.size(); i > 0; i--) {
// 从双端队列的后端移除节点
Node cur = deque.removeLast();
// 将当前节点的值添加到当前层的列表中
list.add(cur.val);
// 获取当前节点的子节点列表
List<Node> childs = cur.children;
// 遍历子节点列表
for (int j = 0; j < childs.size(); j++) {
// 将子节点添加到双端队列的前端,以便下一轮遍历
deque.addFirst(childs.get(j));
}
}
// 将当前层的节点值列表添加到结果列表中
ret.add(list);
}
// 返回包含每层节点值的结果列表
return ret;
}
}
在每个树行中找最大值
515. 在每个树行中找最大值 - 力扣(LeetCode)
java
import java.util.ArrayList;
import java.util.List;
import java.util.ArrayDeque;
/**
* 定义一个二叉树节点。
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 左子节点
TreeNode right; // 右子节点
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 这个方法找出二叉树每一级的最大值,并将它们作为一个列表返回。
*
* @param root 二叉树的根节点。
* @return 一个整数列表,其中每个整数是二叉树某一级别的最大值。
*/
public List<Integer> largestValues(TreeNode root) {
// 初始化一个空列表来存储每一级的最大值。
List<Integer> ret = new ArrayList<>();
// 如果根节点为空,返回一个空列表,因为树中没有值。
if(root == null){
return ret;
}
// 创建一个双端队列来保存二叉树的节点。
// 这将用于执行二叉树的层序遍历。
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
// 将根节点添加到双端队列中。
deque.add(root);
// 继续循环直到双端队列为空,这意味着所有层级都已处理。
while(!deque.isEmpty()){
// 初始化当前层的最大值为最小可能的整数。
int max = Integer.MIN_VALUE;
// 遍历当前层的所有节点。
// 循环从双端队列的大小开始,递减到1。
// 这是因为我们使用的是双端队列,并且节点被添加到队列的前端以供下一层使用。
for(int i = deque.size(); i > 0; i--){
// 移除双端队列中最后添加的节点(当前层的第一个节点)。
TreeNode cur = deque.removeLast();
// 如果当前节点的值大于当前层的最大值,则更新最大值。
max = Math.max(max, cur.val);
// 如果当前节点有左子节点,将其添加到双端队列的前端。
if(cur.left != null){
deque.addFirst(cur.left);
}
// 如果当前节点有右子节点,将其添加到双端队列的前端。
if(cur.right != null){
deque.addFirst(cur.right);
}
}
// 在处理完当前层的所有节点后,将最大值添加到结果列表中。
ret.add(max);
}
// 返回每个层级的最大值列表。
return ret;
}
}
填充每个节点的下一个右侧节点指针
116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)
java
import java.util.ArrayDeque;
import java.util.Queue;
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
}
class Solution {
public Node connect(Node root) {
// 如果根节点为空,直接返回null
if (root == null) {
return null;
}
// 使用双端队列来存储每一层的节点
Queue<Node> deque = new ArrayDeque<>();
// 将根节点添加到队列的开头
deque.addFirst(root);
// 循环直到队列中的所有节点都被处理
while (!deque.isEmpty()) {
// 获取当前层的节点数量
int size = deque.size();
// 初始化前一个节点为null
Node pre = null;
// 遍历当前层的所有节点
for (int i = 0; i < size; i++) {
// 从队列的末尾移除节点(因为添加子节点时是在队列的开头添加,所以这里从末尾移除)
Node cur = deque.removeLast();
// 如果前一个节点不为空,将前一个节点的next指向当前节点
if (pre != null) {
pre.next = cur;
} else {
// 如果前一个节点为空,说明当前节点是当前层的第一个节点,不需要设置next
// 但是需要更新pre为当前节点,以便后续节点的next可以正确设置
pre = cur;
}
// 如果当前节点有左子节点,将其添加到队列的开头
if (cur.left != null) {
deque.addFirst(cur.left);
}
// 如果当前节点有右子节点,将其添加到队列的开头
if (cur.right != null) {
deque.addFirst(cur.right);
}
// 更新pre为当前节点,以便下一次循环时可以正确设置下一个节点的next
pre = cur;
}
// 在每一层的末尾,将前一个节点的next设置为null,因为这是该层的最后一个节点
pre.next = null;
}
// 返回根节点
return root;
}
}
二叉树的最大深度
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
* public class TreeNode {
* int val; // 节点的值
* TreeNode left; // 左子节点
* TreeNode right; // 右子节点
* TreeNode() {} // 默认构造函数
* TreeNode(int val) { this.val = val; } // 构造函数,初始化节点值
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val; // 初始化节点值
* this.left = left; // 初始化左子节点
* this.right = right; // 初始化右子节点
* }
* }
*/
class Solution {
/**
* 计算二叉树的最大深度。
* @param root 二叉树的根节点
* @return 二叉树的最大深度
*/
public int maxDepth(TreeNode root) {
// 如果根节点为空,返回0,表示树为空,深度为0
if(root == null){
return 0;
}
// 初始化最大深度为0
int max = 0;
// 声明当前节点变量
TreeNode cur;
// 使用双端队列来存储待处理的节点
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
// 将根节点加入队列
deque.addFirst(root);
// 当队列不为空时,继续处理
while(!deque.isEmpty()){
// 遍历当前层的所有节点
for(int i = deque.size(); i > 0; i--){
// 取出队列中的最后一个节点
cur = deque.removeLast();
// 如果当前节点的左子节点不为空,将其加入队列的前端
if(cur.left != null){
deque.addFirst(cur.left);
}
// 如果当前节点的右子节点不为空,将其加入队列的前端
if(cur.right != null){
deque.addFirst(cur.right);
}
}
// 每处理完一层,深度加1
max++;
}
// 返回最大深度
return max;
}
}
二叉树的最小深度
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
* public class TreeNode {
* int val; // 节点的值
* TreeNode left; // 左子节点
* TreeNode right; // 右子节点
* TreeNode() {} // 默认构造函数
* TreeNode(int val) { this.val = val; } // 构造函数,初始化节点值
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val; // 初始化节点值
* this.left = left; // 初始化左子节点
* this.right = right; // 初始化右子节点
* }
* }
*/
class Solution {
/**
* 计算二叉树的最小深度。
* @param root 二叉树的根节点
* @return 二叉树的最小深度
*/
public int minDepth(TreeNode root) {
// 如果根节点为空,返回0,表示树为空,深度为0
if(root == null){
return 0;
}
// 初始化深度为0
int depth = 0;
// 声明当前节点变量
TreeNode cur;
// 使用双端队列来存储待处理的节点
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
// 将根节点加入队列
deque.addFirst(root);
// 当队列不为空时,继续处理
while(!deque.isEmpty()){
// 每处理完一层,深度加1
depth++;
// 遍历当前层的所有节点
for(int i = deque.size(); i > 0; i--){
// 取出队列中的最后一个节点
cur = deque.removeLast();
// 如果当前节点的左子节点不为空,将其加入队列的前端
if(cur.left != null){
deque.addFirst(cur.left);
}
// 如果当前节点的右子节点不为空,将其加入队列的前端
if(cur.right != null){
deque.addFirst(cur.right);
}
// 如果当前节点是叶子节点(没有左右子节点),则返回当前深度
if(cur.left == null && cur.right == null){
return depth;
}
}
}
// 如果遍历完所有节点都没有找到叶子节点,返回深度(这种情况在非完全二叉树中可能出现)
return depth;
}
}
找树左下角的值
java
class Solution {
/**
* 找到二叉树中左下角的值。
* @param root 二叉树的根节点
* @return 二叉树左下角的值
*/
public int findBottomLeftValue(TreeNode root) {
// 如果根节点为空,返回0
if(root == null){
return 0;
}
// 使用队列来实现层次遍历
Deque<TreeNode> list = new LinkedList<>();
list.addLast(root); // 将根节点加入队列
TreeNode cur; // 用于存储当前节点
int ret = 0; // 用于存储左下角的值
// 循环直到队列为空
while(true){
int size = list.size(); // 获取当前层的节点数
for(int i = 0; i < size; i++){
cur = list.removeFirst(); // 从队列头部移除一个节点,并存储在cur中
// 如果是当前层的第一个节点,更新ret为当前节点的值
if(i == 0){
ret = cur.val;
}
// 如果当前节点有左子节点,加入队列
if(cur.left != null) {
list.addLast(cur.left);
}
// 如果当前节点有右子节点,加入队列
if(cur.right != null) {
list.addLast(cur.right);
}
}
// 如果队列为空,说明已经到达了最后一层,返回ret
if(list.isEmpty()){
return ret;
}
}
}
}
后序遍历相关题目
对称二叉树
java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
// 调用递归函数compare来比较root的左右子树是否对称
return compare(root.left, root.right);
}
// 1 确定递归函数
boolean compare(TreeNode left, TreeNode right){
// 2 确定终止条件
// 如果左子树为空,右子树不为空,或者左子树不为空,右子树为空,返回false
if(left == null && right != null){
return false;
}
if(left != null && right == null){
return false;
}
// 如果左右子树都为空,说明这两个节点对称,返回true
if(left == null && right == null){
return true;
}
// 如果左右子树的值不相等,说明这两个节点不对称,返回false
if(left.val != right.val){
return false;
}
// 3 处理单步递归逻辑
// 递归比较左子树的左子节点和右子树的右子节点是否对称
boolean leftSame = compare(left.left, right.right);
// 递归比较左子树的右子节点和右子树的左子节点是否对称
boolean rightSame = compare(left.right, right.left);
// 如果两个递归调用都返回true,则说明当前节点的左右子树对称,返回true
return leftSame && rightSame;
}
}
平衡二叉树
java
class Solution {
public boolean isBalanced(TreeNode root) {
int ret = Demo(root); // 调用递归函数,获取树的高度
if(ret == -1){ // 检查返回值是否为-1,表示不平衡
return false; // 如果不平衡,返回false
}else{
return true; // 如果平衡,返回true
}
}
// 1 确定递归函数及返回值
int Demo(TreeNode node){
// 2 确定终止条件
if(node == null){
return 0; // 空节点高度为0
}
// 3 单步递归逻辑
int leftHeight = Demo(node.left); // 递归计算左子树的高度
if(leftHeight == -1){ // 如果左子树不平衡
return -1; // 直接返回-1
}
int rightHeight = Demo(node.right); // 递归计算右子树的高度
if(rightHeight == -1){ // 如果右子树不平衡
return -1; // 直接返回-1
}
// 检查当前节点的左右子树高度差
if(Math.abs(rightHeight - leftHeight) > 1){ // 如果高度差大于1
return -1; // 返回-1,表示不平衡
}else{
// 返回当前节点的高度
return Math.max(rightHeight, leftHeight) + 1; // 当前节点的高度为左右子树最大高度加1
}
}
}
左叶子之和
java
class Solution {
/**
* 计算给定二叉树中所有左叶子节点的值之和。
* @param root 二叉树的根节点。
* @return 所有左叶子节点的值之和。
*/
public int sumOfLeftLeaves(TreeNode root) {
// 如果根节点为空,返回0,因为空树没有叶子节点。
if(root == null){
return 0;
}
// 递归计算左子树中所有左叶子节点的值之和。
int leftSum = sumOfLeftLeaves(root.left);
// 递归计算右子树中所有左叶子节点的值之和。
int rightSum = sumOfLeftLeaves(root.right);
// 初始化中间变量midValue,用于存储当前节点左叶子节点的值。
int midValue = 0;
// 如果当前节点的左子节点不为空,且左子节点没有子节点(即左子节点是叶子节点),
// 则将当前节点的左子节点的值赋给midValue。
if(root.left != null && root.left.left == null && root.left.right == null){
midValue = root.left.val;
}
// 计算总和,包括左子树、右子树中左叶子节点的值之和,以及当前节点的左叶子节点的值(如果有)。
int sum = leftSum + rightSum + midValue;
// 返回所有左叶子节点的值之和。
return sum;
}
}
二叉树的最近公共祖先
236. 二叉树的最近公共祖先 - 力扣(LeetCode)
java
/**
* Definition for a binary tree node.
* 定义二叉树节点
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
/**
* Find the lowest common ancestor of two nodes in a binary tree.
* 在二叉树中找到两个节点的最低公共祖先
* @param root the root of the binary tree
* @param p one of the nodes
* @param q the other node
* @return the lowest common ancestor of p and q
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 如果根节点为空,直接返回null
if(root == null){
return root;
}
// 如果根节点是p或q,那么它就是最低公共祖先
if(root == p || root == q){
return root;
}
// 在左子树中递归查找最低公共祖先
TreeNode leftStatus = lowestCommonAncestor(root.left, p, q);
// 在右子树中递归查找最低公共祖先
TreeNode rightStatus = lowestCommonAncestor(root.right, p, q);
// 如果左右子树都找到了节点,说明p和q在root的两侧,root就是最低公共祖先
if(leftStatus != null && rightStatus != null){
return root;
}
// 如果只在左子树中找到节点,说明p和q都在左子树中,返回左子树中找到的节点
// 同理,如果只在右子树中找到节点,返回右子树中找到的节点
else if(leftStatus != null && rightStatus == null){
return leftStatus;
}else if(leftStatus == null && rightStatus != null){
return rightStatus;
// 如果左右子树都没有找到节点,说明p和q都不在以root为根的子树中,返回null
}else{
return null;
}
}
}
前序遍历相关题目
二叉树的所有路径
java
/**
* Definition for a binary tree node.
* 定义二叉树节点,包含整数值val,左子节点left,和右子节点right。
* 包含三个构造函数,分别用于创建空节点、只有值的节点、以及具有值和左右子节点的节点。
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 使用两个列表,一个用于存储当前路径的节点值,一个用于存储所有路径的字符串表示。
List<Integer> list = new ArrayList<>();
List<String> ret = new ArrayList<>();
/**
* 计算给定二叉树的所有路径。
* @param root 二叉树的根节点。
* @return 包含所有路径的字符串列表。
*/
public List<String> binaryTreePaths(TreeNode root) {
// 如果根节点为空,直接返回空的路径列表。
if(root == null){
return ret;
}
// 调用递归函数来填充路径列表。
Demo(root);
// 返回包含所有路径的列表。
return ret;
}
/**
* 递归函数,用于遍历二叉树并记录所有路径。
* @param node 当前遍历到的节点。
*/
void Demo(TreeNode node){
// 如果节点为空,结束递归。
if(node == null){
return;
}
// 将当前节点的值添加到路径列表中。
list.add(node.val);
// 如果当前节点是一个叶子节点(没有子节点),则将路径添加到结果列表中。
if(node.left == null && node.right == null){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < list.size() - 1; i++){
sb.append(list.get(i) + "->");
}
sb.append(list.get(list.size() - 1));
ret.add(sb.toString());
}
// 递归访问左子节点,并且在返回之前从路径列表中移除当前节点的值。
if(node.left != null){
Demo(node.left);
list.remove(list.size() - 1);
}
// 递归访问右子节点,并且在返回之前从路径列表中移除当前节点的值。
if(node.right != null){
Demo(node.right);
list.remove(list.size() - 1);
}
}
}
路径总和
java
// 定义一个二叉树节点的类
class TreeNode {
int val; // 节点的值
TreeNode left; // 指向左子节点的引用
TreeNode right; // 指向右子节点的引用
// 构造函数,初始化节点的值和左右子节点
TreeNode(int x) {
val = x;
}
}
// 定义一个解法类
class Solution {
// 方法:判断是否存在一条路径,使得路径上所有节点的值之和等于目标和
public boolean hasPathSum(TreeNode root, int targetSum) {
// 如果根节点为空,返回false,因为没有路径
if (root == null) {
return false;
}
// 从目标和中减去当前节点的值
targetSum -= root.val;
// 如果当前节点是叶节点(没有左右子节点),判断目标和是否为0
// 如果为0,说明当前路径的和等于目标和,返回true
if (root.left == null && root.right == null) {
return targetSum == 0;
}
// 如果当前节点有左子节点,递归调用hasPathSum方法检查左子树
if (root.left != null) {
boolean leftSum = hasPathSum(root.left, targetSum);
// 如果左子树中存在符合条件的路径,返回true
if (leftSum) {
return true;
}
}
// 如果当前节点有右子节点,递归调用hasPathSum方法检查右子树
if (root.right != null) {
boolean rightSum = hasPathSum(root.right, targetSum);
// 如果右子树中存在符合条件的路径,返回true
if (rightSum) {
return true;
}
}
// 如果当前节点的左右子树中都没有符合条件的路径,返回false
return false;
}
}
其他类题型
按照一定规则构建二叉树
从中序与后序遍历序列构造二叉树
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
Map<Integer, Integer> map; // 用于存储中序遍历中每个节点值对应的索引
public TreeNode buildTree(int[] inorder, int[] postorder) {
map = new HashMap<>(); // 初始化哈希表
for(int i = 0; i < inorder.length; i++){ // 填充哈希表
map.put(inorder[i], i);
}
return findNode(inorder, 0, inorder.length, postorder, 0, postorder.length); // 调用递归函数构建树
}
TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd){
// 如果当前子树的范围无效,则返回null
if(inBegin >= inEnd || postBegin >= postEnd){
return null;
}
// 获取后序遍历中最后一个元素,即当前子树的根节点
int rootValue = postorder[postEnd - 1];
// 获取根节点在中序遍历中的索引
int rootIndex = map.get(rootValue);
// 计算左子树的长度
int leftLen = rootIndex - inBegin;
// 创建当前子树的根节点
TreeNode root = new TreeNode(rootValue);
// 递归构建左子树
root.left = findNode(inorder, inBegin, rootIndex, postorder, postBegin, postBegin + leftLen);
// 递归构建右子树
root.right = findNode(inorder, rootIndex + 1, inEnd, postorder, postBegin + leftLen, postEnd - 1);
// 返回当前子树的根节点
return root;
}
}
从前序与中序遍历序列构造二叉树
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
Map<Integer, Integer> map; // 用于存储中序遍历中每个节点值对应的索引
/**
* 根据给定的前序遍历和中序遍历数组构建二叉树。
* @param preorder 前序遍历数组
* @param inorder 中序遍历数组
* @return 构建的二叉树的根节点
*/
public TreeNode buildTree(int[] preorder, int[] inorder) {
map = new HashMap<>(); // 初始化哈希表
for(int i = 0; i < inorder.length; i++){ // 填充哈希表
map.put(inorder[i], i);
}
return findNode(preorder, 0, preorder.length, inorder, 0, inorder.length); // 调用递归函数构建树
}
/**
* 递归函数,用于构建二叉树。
* @param preorder 前序遍历数组
* @param preBegin 前序遍历的开始索引
* @param preEnd 前序遍历的结束索引
* @param inorder 中序遍历数组
* @param inBegin 中序遍历的开始索引
* @param inEnd 中序遍历的结束索引
* @return 当前子树的根节点
*/
TreeNode findNode(int[] preorder, int preBegin, int preEnd, int[] inorder, int inBegin, int inEnd){
// 如果当前子树的范围无效,则返回null
if(preBegin >= preEnd || inBegin >= inEnd){
return null;
}
// 获取前序遍历中的第一个元素,即当前子树的根节点
int rootValue = preorder[preBegin];
// 获取根节点在中序遍历中的索引
int rootIndex = map.get(rootValue);
// 计算左子树的长度
int leftLen = rootIndex - inBegin;
// 创建当前子树的根节点
TreeNode root = new TreeNode(rootValue);
// 递归构建左子树
// 注意这里的范围是 [preBegin + 1, preBegin + leftLen + 1),因为前序遍历中根节点之后紧接着是左子树
root.left = findNode(preorder, preBegin + 1, preBegin + leftLen + 1, inorder, inBegin, rootIndex);
// 递归构建右子树
// 右子树的开始索引是 preBegin + leftLen + 1,因为左子树之后是右子树
root.right = findNode(preorder, preBegin + leftLen + 1, preEnd, inorder, rootIndex + 1, inEnd);
// 返回当前子树的根节点
return root;
}
}
最大二叉树
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 左子节点
TreeNode right; // 右子节点
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 主函数,用于构建最大二叉树。
* @param nums 整数数组,表示二叉树的节点值。
* @return 构建的最大二叉树的根节点。
*/
public TreeNode constructMaximumBinaryTree(int[] nums) {
// 如果数组为空或为null,则返回null
if (nums == null || nums.length == 0) {
return null;
}
// 调用递归函数,从数组的开始到结束构建树
return createTree(nums, 0, nums.length);
}
/**
* 递归函数,用于构建最大二叉树。
* @param nums 整数数组,表示二叉树的节点值。
* @param begin 开始索引(包含)。
* @param end 结束索引(不包含)。
* @return 当前子树的根节点。
*/
TreeNode createTree(int[] nums, int begin, int end) {
// 如果开始索引大于或等于结束索引,表示当前子树为空,返回null
if (begin >= end) {
return null;
}
// 初始化根节点的值为最小整数,这样可以确保找到最大的值
int rootValue = Integer.MIN_VALUE;
// 初始化根节点的索引
int rootIndex = 0;
// 遍历当前子树的范围,找到最大的值及其索引
for (int i = begin; i < end; i++) {
if (rootValue < nums[i]) {
rootValue = nums[i];
rootIndex = i;
}
}
// 创建当前子树的根节点
TreeNode root = new TreeNode(rootValue);
// 递归构建左子树,左子树的范围是开始索引到根节点索引
root.left = createTree(nums, begin, rootIndex);
// 递归构建右子树,右子树的范围是根节点索引的下一个到结束索引
root.right = createTree(nums, rootIndex + 1, end);
// 返回当前子树的根节点
return root;
}
}
合并二叉树
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 左子节点
TreeNode right; // 右子节点
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 主函数,用于合并两棵二叉树。
* @param root1 第一棵树的根节点。
* @param root2 第二棵树的根节点。
* @return 合并后的二叉树的根节点。
*/
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
// 调用递归函数合并两棵树
return Demo(root1, root2);
}
/**
* 递归函数,用于合并两棵二叉树。
* 在合并过程中,对应位置的节点值相加,左子树和右子树分别合并。
* @param root1 第一棵树的根节点。
* @param root2 第二棵树的根节点。
* @return 合并后的二叉树的根节点。
*/
TreeNode Demo(TreeNode root1, TreeNode root2) {
// 如果第一棵树为空,且第二棵树不为空,返回第二棵树的根节点
if (root1 == null && root2 != null) {
return root2;
}
// 如果第一棵树不为空,且第二棵树为空,返回第一棵树的根节点
if (root1 != null && root2 == null) {
return root1;
}
// 如果两棵树都为空,返回null
if (root1 == null && root2 == null) {
return null;
}
// 如果两棵树都不为空,创建一个新的根节点,其值为两个根节点值的和
TreeNode root = new TreeNode(root1.val + root2.val);
// 递归地合并左子树
root.left = Demo(root1.left, root2.left);
// 递归地合并右子树
root.right = Demo(root1.right, root2.right);
// 返回合并后的二叉树的根节点
return root;
}
}
二叉搜索树相关题目
中序遍历二叉搜索树是从小到大的!!!
二叉搜索树中的搜索
java
/**
* Definition for a binary tree node.
* 定义二叉树节点。
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 左子节点
TreeNode right; // 右子节点
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
/**
* 在二叉搜索树中搜索给定的值。
* @param root 二叉搜索树的根节点。
* @param val 要搜索的值。
* @return 搜索到的节点,如果未找到则返回null。
*/
public TreeNode searchBST(TreeNode root, int val) {
// 如果根节点为空,说明树为空,返回null
if (root == null) {
return null;
}
// 如果根节点的值大于要搜索的值,说明目标值在左子树中
if (root.val > val) {
return searchBST(root.left, val);
}
// 如果根节点的值小于要搜索的值,说明目标值在右子树中
else if (root.val < val) {
return searchBST(root.right, val);
}
// 如果根节点的值等于要搜索的值,说明已经找到目标节点
else if (root.val == val) {
return root;
}
// 如果以上条件都不满足,说明未找到目标值,返回null
return null;
}
}
验证二叉搜索树
中序遍历二叉搜索树是从小到大的!!!
java
/**
* 定义一个二叉树节点。
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决方案类,用于验证二叉树是否为有效的二叉搜索树。
*/
class Solution {
// 用于记录前一个遍历到的节点,以便在中序遍历中检查节点的顺序性。
TreeNode preNode = null;
/**
* 验证以 root 为根的二叉树是否为有效的二叉搜索树。
* @param root 二叉树的根节点
* @return 如果是有效的二叉搜索树,返回 true;否则返回 false。
*/
public boolean isValidBST(TreeNode root) {
// 如果当前节点为空,说明已经到达叶子节点的下一层,返回 true。
if (root == null) {
return true;
}
// 首先递归检查左子树是否为有效的二叉搜索树。
boolean leftStatus = isValidBST(root.left);
// 如果前一个节点不为空,并且当前节点的值小于等于前一个节点的值,
// 说明树不是有效的二叉搜索树,返回 false。
if (preNode != null && root.val <= preNode.val) {
return false;
}
// 将当前节点设置为前一个节点,以供后续节点比较。
preNode = root;
// 递归检查右子树是否为有效的二叉搜索树。
boolean rightStatus = isValidBST(root.right);
// 如果左右子树都为有效的二叉搜索树,返回 true,否则返回 false。
return rightStatus && leftStatus;
}
}
二叉搜索树的最小绝对差
530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)
java
/**
* 定义一个二叉树节点。
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 解决方案类,用于计算二叉树中任意两个值之间的最小差值。
*/
class Solution {
// 用于存储当前找到的最小差值,初始化为最大整数。
int ret = Integer.MAX_VALUE;
// 用于记录上一次访问的节点。
TreeNode pre = null;
/**
* 计算以 root 为根的二叉树中任意两个值之间的最小差值。
* @param root 二叉树的根节点
* @return 最小差值
*/
public int getMinimumDifference(TreeNode root) {
// 调用递归方法来遍历树并计算最小差值。
Demo(root);
// 返回计算出的最小差值。
return ret;
}
/**
* 递归方法,用于遍历二叉树并计算最小差值。
* @param root 当前节点
*/
void Demo(TreeNode root) {
if (root == null) {
// 如果当前节点为空,直接返回。
return;
}
// 首先递归遍历左子树。
Demo(root.left);
// 如果前一个节点不为空,计算当前节点与前一个节点的差值,并更新最小差值。
if (pre != null) {
ret = Math.min(ret, root.val - pre.val);
}
// 更新前一个节点为当前节点。
pre = root;
// 递归遍历右子树。
Demo(root.right);
}
}
二叉搜索树中的众数
java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 用于存储出现次数最多的元素
List<Integer> ret;
// 当前节点出现的次数
int count = 0;
// 出现次数最多的节点的次数
int maxCount = 0;
// 前一个节点的引用,用于比较当前节点和前一个节点的值是否相同
TreeNode pre;
/**
* 找出二叉树中出现次数最多的元素
* @param root 二叉树的根节点
* @return 出现次数最多的元素数组
*/
public int[] findMode(TreeNode root) {
// 初始化返回列表
ret = new ArrayList<Integer>();
// 调用DFS方法遍历二叉树
Demo(root);
// 将结果列表转换为数组
int result[] = new int[ret.size()];
for(int i = 0; i < ret.size(); i++){
result[i] = ret.get(i);
}
return result;
}
/**
* 深度优先搜索方法,用于遍历二叉树并找出出现次数最多的元素
* @param cur 当前节点
*/
void Demo(TreeNode cur){
if(cur == null){
// 如果当前节点为空,直接返回
return;
}
// 先遍历左子树
Demo(cur.left);
// 如果前一个节点为空,或者当前节点的值和前一个节点的值相同,则增加计数
if(pre == null){
count = 1;
}else if(pre.val == cur.val){
count++;
}else{
// 如果当前节点的值和前一个节点的值不同,则重置计数
count = 1;
}
// 更新前一个节点为当前节点
pre = cur;
// 如果当前节点的计数等于最大计数,则将当前节点的值添加到结果列表中
if(count == maxCount){
ret.add(cur.val);
}
// 如果当前节点的计数大于最大计数,则清空结果列表,并添加当前节点的值
if(count > maxCount){
ret.clear();
ret.add(cur.val);
// 更新最大计数
maxCount = count;
}
// 遍历右子树
Demo(cur.right);
}
}
二叉搜索树的最近公共祖先
235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)
java
/**
* Definition for a binary tree node.
* 定义二叉树节点类。
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
/**
* Solution class that contains the method to find the lowest common ancestor of two nodes in a binary tree.
* 解决方案类,包含寻找二叉树中两个节点的最低公共祖先的方法。
*/
class Solution {
/**
* This method finds the lowest common ancestor of two nodes p and q in a binary tree.
* 此方法在二叉树中找到两个节点p和q的最低公共祖先。
*
* @param root the root of the binary tree.
* @param p one of the nodes to find the lowest common ancestor for.
* @param q the other node to find the lowest common ancestor for.
* @return the lowest common ancestor node.
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 如果根节点为空,则返回null。
if(root == null){
return null;
}
// 如果根节点的值大于p和q的值,说明p和q都在左子树。
if(root.val > p.val && root.val > q.val){
// 递归地在左子树中寻找最低公共祖先。
TreeNode left = lowestCommonAncestor(root.left, p, q);
// 如果在左子树中找到了最低公共祖先,则返回它。
if(left != null){
return left;
}
}
// 如果根节点的值小于p和q的值,说明p和q都在右子树。
if(root.val < p.val && root.val < q.val){
// 递归地在右子树中寻找最低公共祖先。
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 如果在右子树中找到了最低公共祖先,则返回它。
if(right != null){
return right;
}
}
// 如果以上两种情况都不满足,说明p和q一个在左子树,一个在右子树,或者p和q中的一个就是根节点。
// 在这种情况下,根节点就是p和q的最低公共祖先。
return root;
}
}
二叉搜索树中的插入操作
701. 二叉搜索树中的插入操作 - 力扣(LeetCode)
java
/**
* 定义一个二叉树节点。
*/
public class TreeNode {
int val; // 节点的值
TreeNode left; // 指向左子节点的引用
TreeNode right; // 指向右子节点的引用
// 构造函数
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 实现将一个值插入到二叉搜索树中的操作。
*/
class Solution {
/**
* 将值 val 插入到以 root 为根的二叉搜索树中。
* @param root 二叉搜索树的根节点。
* @param val 要插入的值。
* @return 插入新值后的二叉搜索树的根节点。
*/
public TreeNode insertIntoBST(TreeNode root, int val) {
// 如果根节点为空,说明树是空的,直接创建一个新节点作为树的根。
if(root == null){
return new TreeNode(val);
}
// 如果要插入的值小于当前节点的值,说明新节点应该在左子树中。
if(root.val > val){
// 递归地在左子树中插入新值。
root.left = insertIntoBST(root.left, val);
}
// 如果要插入的值大于当前节点的值,说明新节点应该在右子树中。
else if(root.val < val){
// 递归地在右子树中插入新值。
root.right = insertIntoBST(root.right, val);
}
// 如果要插入的值等于当前节点的值,二叉搜索树不允许有重复值,所以不进行任何操作。
// 返回根节点,此时树可能已经更新(如果插入了新节点)。
return root;
}
}
删除二叉搜索树中的节点
450. 删除二叉搜索树中的节点 - 力扣(LeetCode)
java
/**
* 实现在二叉搜索树中删除一个节点的操作。
*/
public class Solution {
/**
* 在以 root 为根的二叉搜索树中删除值为 key 的节点。
* @param root 二叉搜索树的根节点。
* @param key 要删除的节点的值。
* @return 删除节点后的二叉搜索树的根节点。
*/
public TreeNode deleteNode(TreeNode root, int key) {
// 如果根节点为空,说明没有找到要删除的节点,直接返回null。
if(root == null){
return null;
}
// 如果当前节点的值等于要删除的值,需要进行删除操作。
if(root.val == key){
// 如果当前节点没有左右孩子,直接返回null,表示删除该节点。
if(root.left == null && root.right == null){
return null;
}
// 如果当前节点只有右孩子,返回右孩子,替代当前节点。
else if(root.left == null && root.right != null){
return root.right;
}
// 如果当前节点只有左孩子,返回左孩子,替代当前节点。
else if(root.left != null && root.right == null){
return root.left;
}
// 如果当前节点既有左孩子又有右孩子,找到右子树中最小的节点(最左下的节点),
// 将其值复制到当前节点,然后递归地删除那个最小的节点。
else{
TreeNode cur = root.right;
while(cur.left != null){
cur = cur.left;
}
cur.left = root.left;
root = root.right;
return root;
}
}
// 如果当前节点的值大于要删除的值,说明要删除的节点在左子树中,递归地在左子树中删除。
if(root.val > key){
root.left = deleteNode(root.left, key);
}
// 如果当前节点的值小于要删除的值,说明要删除的节点在右子树中,递归地在右子树中删除。
if(root.val < key){
root.right = deleteNode(root.right, key);
}
// 返回根节点,此时树可能已经更新(如果插入了新节点),或者当前节点不是要删除的值。
return root;
}
}
修剪二叉搜索树
java
class Solution {
// 修剪二叉搜索树,使其只包含值在 [low, high] 范围内的节点
public TreeNode trimBST(TreeNode root, int low, int high) {
// 如果当前节点为空,直接返回 null
if(root == null){
return root;
}
// 如果当前节点的值大于 high,则只需要考虑左子树
if(root.val > high){
// 递归修剪左子树
return trimBST(root.left, low, high);
}
// 如果当前节点的值小于 low,则只需要考虑右子树
if(root.val < low){
// 递归修剪右子树
return trimBST(root.right, low, high);
}
// 如果当前节点的值在 [low, high] 范围内,则保留该节点
// 递归修剪左子树,确保左子树中的所有节点值也在 [low, high] 范围内
root.left = trimBST(root.left, low, high);
// 递归修剪右子树,确保右子树中的所有节点值也在 [low, high] 范围内
root.right = trimBST(root.right, low, high);
// 返回当前节点,此时当前节点及其子树已经满足条件
return root;
}
}
将有序数组转换为二叉搜索树
108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
java
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return createTree(nums, 0, nums.length - 1);
}
// 使用左闭右闭区间 [left, right] 来构建子树
private TreeNode createTree(int[] nums, int left, int right) {
if (left > right) {
return null;
}
// 计算中间索引,创建根节点
int mid = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[mid]);
// 递归构建左子树和右子树
root.left = createTree(nums, left, mid - 1);
root.right = createTree(nums, mid + 1, right);
return root;
}
}
把二叉搜索树转换为累加树
1038. 从二叉搜索树到更大和树 - 力扣(LeetCode)
java
class Solution {
// 用于存储当前节点的累计和
int sum = 0;
// 主函数,用于开始转换过程
public TreeNode bstToGst(TreeNode root) {
// 调用辅助函数进行转换
Demo(root);
// 返回转换后的树的根节点
return root;
}
// 辅助函数,用于递归地转换树
void Demo(TreeNode root) {
// 基本情况:如果节点为空,直接返回
if (root == null) {
return;
}
// 先递归地处理右子树
bstToGst(root.right);
// 将当前节点的值加到累计和中
sum += root.val;
// 更新当前节点的值为累计和
root.val = sum;
// 再递归地处理左子树
bstToGst(root.left);
}
}