数据结构-二叉树笔记

递归三部曲!!!

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

模板题

226. 翻转二叉树 - 力扣(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 {
    //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;

    }
}

模板

递归模板

前序遍历

144. 二叉树的前序遍历 - 力扣(LeetCode)

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); // 递归遍历右子树
    }
}

后序遍历

145. 二叉树的后序遍历 - 力扣(LeetCode)

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); // 将当前节点的值添加到结果列表中
    }
}

中序遍历

94. 二叉树的中序遍历 - 力扣(LeetCode)

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); // 递归遍历右子树
    }
}

迭代版本

前序遍历

144. 二叉树的前序遍历 - 力扣(LeetCode)

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; // 返回遍历结果
    }
}

中序遍历

94. 二叉树的中序遍历 - 力扣(LeetCode)

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; // 返回遍历结果
    }
}

层序遍历

102. 二叉树的层序遍历 - 力扣(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;
    }
}

/**
 * 解决方案类,包含 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;
    }
}

层序遍历相关题目

二叉树的右视图

199. 二叉树的右视图 - 力扣(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;
    }
}

/**
 * 解决方案类,包含 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;
    }
}

二叉树的层平均值

637. 二叉树的层平均值 - 力扣(LeetCode)

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叉树的层序遍历

429. N 叉树的层序遍历 - 力扣(LeetCode)

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;
    }
}

二叉树的最大深度

104. 二叉树的最大深度 - 力扣(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 {
    /**
     * 计算二叉树的最大深度。
     * @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;
    }
}

二叉树的最小深度

111. 二叉树的最小深度 - 力扣(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 {
    /**
     * 计算二叉树的最小深度。
     * @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;
    }
}

找树左下角的值

513. 找树左下角的值 - 力扣(LeetCode)

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;
            }
        }
    }
}

后序遍历相关题目

对称二叉树

101. 对称二叉树 - 力扣(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 {
    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;
    }
}

平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode)

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
        }
    }
}

左叶子之和

404. 左叶子之和 - 力扣(LeetCode)

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;
        }
    }
}

前序遍历相关题目

二叉树的所有路径

257. 二叉树的所有路径 - 力扣(LeetCode)

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);
        }
    }
}

路径总和

112. 路径总和 - 力扣(LeetCode)

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;
    }
}

最大二叉树

654. 最大二叉树 - 力扣(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 {
    /**
     * 主函数,用于构建最大二叉树。
     * @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;
    }
}

合并二叉树

617. 合并二叉树 - 力扣(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 {
    /**
     * 主函数,用于合并两棵二叉树。
     * @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;
    }
}

二叉搜索树相关题目

中序遍历二叉搜索树是从小到大的!!!

二叉搜索树中的搜索

700. 二叉搜索树中的搜索 - 力扣(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 {
    /**
     * 在二叉搜索树中搜索给定的值。
     * @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;
    }
}

验证二叉搜索树

中序遍历二叉搜索树是从小到大的!!!

98. 验证二叉搜索树 - 力扣(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 {
    // 用于记录前一个遍历到的节点,以便在中序遍历中检查节点的顺序性。
    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);
    }
}

二叉搜索树中的众数

501. 二叉搜索树中的众数 - 力扣(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 {

    // 用于存储出现次数最多的元素
    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;
    }
}

修剪二叉搜索树

669. 修剪二叉搜索树 - 力扣(LeetCode)

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);
    }
}
相关推荐
冷眼看人间恩怨4 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
菜鸡中的奋斗鸡→挣扎鸡4 小时前
滑动窗口 + 算法复习
数据结构·算法
axxy20005 小时前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
Uu_05kkq7 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
1nullptr8 小时前
三次翻转实现数组元素的旋转
数据结构
TT哇9 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
A懿轩A9 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
Hejjon10 小时前
SpringBoot 整合 SQLite 数据库
笔记
1 9 J10 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
汝即来归10 小时前
选择排序和冒泡排序;MySQL架构
数据结构·算法·排序算法