代码随想录刷题-二叉树

该博客围绕二叉树展开,涵盖遍历方式(递归、迭代、层序)、求属性(对称、深度、节点个数等)、修改与构造(翻转、合并等)、公共祖先问题以及二叉搜索树的属性与修改构造等内容,每个部分都给出对应题目、链接及代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.二叉树的遍历方式

2-144.二叉树的递归遍历🟢

题目:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

链接:144. 二叉树的前序遍历

代码:

class Solution {  
    public List<Integer> preorderTraversal(TreeNode root) {  
        List<Integer> res = new ArrayList<Integer>();  
        traversal(root, res);  
        return res;  
    }  
  
    public void traversal(TreeNode root, List<Integer> res) {  
        if (root == null) {  
            return;  
        }  
        res.add(root.val); // 中(放到中间就是中序遍历,放到最下边就是后序遍历)
        traversal(root.left, res); // 左 
        traversal(root.right, res);  // 右
    }  
}

3-144.二叉树的迭代遍历🟢

题目:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

链接:144. 二叉树的前序遍历

代码:

class Solution {
    // 前序遍历顺序:中-左-右,入栈顺序:中-右-左
    // 首先将根入栈,因为栈是FILO,所以要先将右结点入栈,再将左结点入栈
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        Deque<TreeNode> stack = new LinkedList<>();
        if (root == null) return res;
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop(); // 中
            res.add(node.val);
            if (node.right != null) {
                stack.push(node.right); // 右
            }
            if (node.left != null) {
                stack.push(node.left);  // 左
            }
        }
        return res;
    }
}

后序迭代方式遍历代码:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        // 前序遍历返回的res是根左右,如果调换while中右左入栈的顺序
        // 就会得到根右左顺序的res,将res反转就会得到左右根
        List<Integer> res = new LinkedList<>();
        if (root == null) return res;
        Deque<TreeNode> stack = new LinkedList<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();  // 中
            res.add(node.val);
            if (node.left != null) {
                stack.push(node.left); // 左
            }
            if (node.right != null) {
                stack.push(node.right);  // 右
            }
        }
        Collections.reverse(res); // 反转
        return res;
    }
}

中序迭代方式遍历代码:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        // 首先判断当前结点是否为空,不为空将当前结点的左结点入栈,
        // 若为空,取栈顶元素加入res,将栈顶元素的右结点作为当前结点
        // 继续重复上面步骤,直到当前结点为空且栈为空为止。
        List<Integer> res = new LinkedList<>();
        if (root == null) return res;
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node);
                node = node.left;
            } else {
                node = stack.pop();
                res.add(node.val);
                node = node.right;
            }
        }
        return res;
    }
}

5-102.二叉树的层序遍历🟡

题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

链接:二叉树的层序遍历

代码:

class Solution {  
    public List<List<Integer>> levelOrder(TreeNode root) {  
        List<List<Integer>> res = new LinkedList<>();  
        if (root == null) {  
            return res;  
        }  
  
        Queue<TreeNode> q = new LinkedList<>();  
        q.offer(root);  
        // while 循环控制从上向下一层层遍历  
        while (!q.isEmpty()) {  
            int len = q.size();  
            // 记录这一层的节点值  
            List<Integer> level = new LinkedList<>();  
            // for 循环控制每一层从左向右遍历  
            for (int i = 0; i < len; i++) {  
                TreeNode cur = q.poll();  
                level.add(cur.val);  
                if (cur.left != null)  
                    q.offer(cur.left);  
                if (cur.right != null)  
                    q.offer(cur.right);  
            }  
            res.add(level);  
        }  
        return res;  
    }  
}

2.求二叉树的属性

8-101.对称二叉树🟢

题目:给你一个二叉树的根节点 root ,检查它是否轴对称。

链接:101. 对称二叉树

代码:

class Solution {
    public boolean isSymmetric(TreeNode root) {
        // 对称二叉树,对称的是根的左右子树
        // 不能完全遍历左右子树之后比较遍历结果,因为不能区分左结点或右结点为空的情况
        // 左子树通过根左右的方式遍历
        // 右子树通过根右左的方式遍历
        // 若左右子树遍历的结果相同,则是对称二叉树
        TreeNode left = root.left;
        TreeNode right = root.right;
        return inorder(left, right);
    }

    public boolean inorder(TreeNode left, TreeNode right) {
        if (left == null && right != null) return false;
        if (left != null && right == null) return false;
        if (left == null && right == null) return true;
        if (left.val != right.val) return false;
        //前序遍历
        boolean f1 = inorder(left.left, right.right);
        boolean f2 = inorder(left.right, right.left);
        return f1 && f2;
    }
}

9-104.二叉树的最大深度🟢

题目:给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

链接:104. 二叉树的最大深度

代码:

class Solution {
    public int maxDepth(TreeNode root) {
        // 求二叉树的深度本质上是遍历二叉树
        // 这里使用后序遍历求二叉树的深度
        if (root == null) return 0;
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        return 1 + Math.max(leftDepth, rightDepth);
    }
}

10-111.二叉树的最小深度🟢

题目:给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

链接:111. 二叉树的最小深度

代码:

class Solution {
    /**
     * 递归法,相比求MaxDepth要复杂点
     * 因为最小深度是从根节点到最近叶子节点的最短路径上的节点数量
     */
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);
        if (root.left == null) {
            return rightDepth + 1;
        }
        if (root.right == null) {
            return leftDepth + 1;
        }
        // 左右结点都不为null
        return Math.min(leftDepth, rightDepth) + 1;
    }
}

11-222.完全二叉树的节点个数🟢

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

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

链接:222. 完全二叉树的节点个数

代码:

1.通用解法

class Solution {
    // 通用递归解法
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}

2.针对完全二叉树的解法

class Solution {
    // 满二叉树的结点数为:2^depth - 1
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        TreeNode left = root.left;
        TreeNode right = root.right;
        int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
        while (left != null) {  // 求左子树深度
            left = left.left;
            leftDepth++;
        }
        while (right != null) { // 求右子树深度
            right = right.right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}

12-110.平衡二叉树🟢

题目:给定一个二叉树,判断它是否是高度平衡的二叉树

链接:110. 平衡二叉树

代码:

class Solution {  
    public boolean isBalanced(TreeNode root) {   
        return height(root) >= 0;  
    }  
    // 定义:给一个根节点,返回它的高度,负数代表该树不平衡
    public int height(TreeNode root) {  
        if (root == null) {  
            return 0;  
        }  
        int leftHeight = height(root.left);  
        int rightHeight = height(root.right);  
        // 如果高度差大于1返回-1表示当前子树不平衡  
        // 上一级的父节点获取到子节点返回的-1后也返回-1,表示父节点同样也是不平衡的  
        if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {  
            return -1;  
        } else {  
            return Math.max(leftHeight, rightHeight) + 1;  
        }  
    }  
}

13-257.二叉树的所有路径🟢

题目:给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

链接:二叉树的所有路径

代码:

class Solution {  
    List<String> res = new ArrayList<>();  
    public List<String> binaryTreePaths(TreeNode root) {  
        if(root == null) return new ArrayList<>();  
        // 参数:根节点 当前遍历路径  
        traversal(root, "");  
        return res;  
    }  
  
    public void traversal(TreeNode root, String path) {  
        // 递归结束条件是遇到叶子节点,则将当前路径添加到结果中  
        if(root.left == null && root.right == null){  
            res.add(new StringBuilder(path).append(root.val).toString());  
            return;  
        }  
        String tmp = new StringBuilder(path).append(root.val).append("->").toString();  
        if(root.left != null) traversal(root.left,tmp);  
        if(root.right != null) traversal(root.right,tmp);  
    }  
}

15-404.左叶子之和🟢

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

链接:左叶子之和

代码:

class Solution {  
    int res =0;  
    public int sumOfLeftLeaves(TreeNode root) {  
        traversal(root);  
        return res;  
    }  
    public void traversal(TreeNode root){  
        if(root == null){  
            return;  
        }  
        // 前序遍历,判断当前根节点的左子节点是不是左叶子  
        if(root.left!=null&&root.left.left==null&&root.left.right==null){  
            res += root.left.val;  
        }  
        traversal(root.left);  
        traversal(root.right);  
    }  
}

16-513.找树左下角的值🟡

题目:给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。

链接:找树左下角的值

代码:

1.递归解法(不推荐)

class Solution {  
    int maxDeep = -1;  
    int res = 0;  
    public int findBottomLeftValue(TreeNode root) {  
        traversal(root,0);  
        return res;  
    }  
  
    public void traversal (TreeNode root,int deep) {  
        if (root == null)  
            return;
        // 遇到叶子节点开始判断  
        if (root.left == null && root.right == null) {  
            // 先左后右,所以可以直接判断当前高度是否大于最大高度  
            if (deep > maxDeep) {  
                res = root.val;  
                maxDeep = deep;  
            }  
        }  
        traversal(root.left,deep + 1);  
        traversal(root.right,deep + 1);  
    }  
}

2.迭代解法(推荐)

class Solution {  
    public int findBottomLeftValue(TreeNode root) {  
        int res = root.val;  
        Queue<TreeNode> q = new LinkedList<>();  
        q.offer(root);  
        // while 循环控制从上向下一层层遍历  
        while (!q.isEmpty()) {  
            int len = q.size();  
            // for 循环控制每一层从左向右遍历  
            for (int i = 0; i < len; i++) {  
                TreeNode cur = q.poll();  
                // 这一层的第一个节点也就是最左边的  
                if(i == 0){  
                    res = cur.val;  
                }  
                if (cur.left != null)  
                    q.offer(cur.left);  
                if (cur.right != null)  
                    q.offer(cur.right);  
            }  
        }  
        return res;  
    }  
}

17-112.路径总和🟢

题目:给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

链接:路径总和

代码:

1.我的解法(易理解但不推荐)

class Solution {  
    boolean res = false;  
    public boolean hasPathSum(TreeNode root, int targetSum) {  
        traversal(root,0,targetSum);  
        return res;  
    }
    // 对树做前序遍历,但若找到则不再进行后续遍历  
    public void traversal(TreeNode root,int sum,int targetSum){  
        // 节点为空或已经找到了路径就直接返回
        // 我是手动判断下!res时不再递归,但可以给函数设置返回值停止后续递归  
        if(root == null || res){  
            return;  
        }  
        // 是叶子节点且累加值等于目标值  
        if(root.left == null && root.right == null && root.val+sum == targetSum){  
            res = true;  
        }  
        int tmp = root.val+sum;  
        traversal(root.left,tmp,targetSum);  
        traversal(root.right,tmp,targetSum);  
    }  
}

2.官方解法(推荐)

class Solution {  
    public boolean hasPathSum(TreeNode root, int sum) {  
        if (root == null) {  
            return false;  
        }  
        // 碰到叶子节点判断当前剩余值是否等于叶子节点值  
        if (root.left == null && root.right == null) {  
            return sum == root.val;  
        }  
        // 在递归函数里操作sum,相当于返回的时候会回溯到之前的状态
        // 如果左子树或右子树中找到了路径就直接返回true,程序就不再继续遍历剩下路径了  
        return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);  
    }  
}

扩展:113.路径总和

题目:给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

链接:路径总和 II

代码:

class Solution {  
    List<List<Integer>> res = new LinkedList<List<Integer>>();  
    Deque<Integer> path = new LinkedList<Integer>();  
  
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {  
        traversal(root, targetSum);  
        return res;  
    }  
  
    public void traversal(TreeNode root, int targetSum) {  
        if (root == null) {  
            return;  
        }  
        path.offerLast(root.val);  
        targetSum -= root.val;  
        if (root.left == null && root.right == null && targetSum == 0) {  
            res.add(new LinkedList<Integer>(path));  
        }  
        traversal(root.left, targetSum);  
        traversal(root.right, targetSum);  
        // 弹出一个元素相当于回溯到之前的状态  
        path.pollLast();  
    }  
}

3.二叉树的修改与构造

6-226.翻转二叉树🟢

题目:给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

链接:226. 翻转二叉树

代码:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        // 翻转二叉树,实际上就是交换左右结点
        // 使用递归来交换,根左右
        if(root == null) return null;
        swapChildren(root);
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
    public void swapChildren(TreeNode root){
        TreeNode temp = root.right;
        root.right = root.left;
        root.left = temp;
    }
}

18-106.从中序与后序遍历序列构造二叉树🟡

题目:给定两个整数数组 inorderpostorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树

链接:从中序与后序遍历序列构造二叉树

代码:

class Solution {  
    // 存储 inorder 中值到索引的映射  
    HashMap<Integer, Integer> valToIndex = new HashMap<>();  
  
    public TreeNode buildTree(int[] inorder, int[] postorder) {  
        for (int i = 0; i < inorder.length; i++) {  
            valToIndex.put(inorder[i], i);  
        }  
        return build(inorder, 0, inorder.length - 1,  
                postorder, 0, postorder.length - 1);  
    }  
  
    /*  
       定义:  
       中序遍历数组为 inorder[inStart..inEnd],  
       后序遍历数组为 postorder[postStart..postEnd],  
       构造这个二叉树并返回该二叉树的根节点  
    */    
    public TreeNode build(int[] inorder, int inStart, int inEnd,  
                   int[] postorder, int postStart, int postEnd) {  
  
        if (inStart > inEnd) {  
            return null;  
        }  
        // root 节点对应的值就是后序遍历数组的最后一个元素  
        int rootVal = postorder[postEnd];  
        // rootVal 在中序遍历数组中的索引  
        int index = valToIndex.get(rootVal);  
        // 左子树的节点个数  
        int leftSize = index - inStart;  
        TreeNode root = new TreeNode(rootVal);  
  
        // 递归构造左右子树  
        root.left = build(inorder, inStart, index - 1,  
                postorder, postStart, postStart + leftSize - 1);  
  
        root.right = build(inorder, index + 1, inEnd,  
                postorder, postStart + leftSize, postEnd - 1);  
        return root;  
    }  
}

19-654.最大二叉树🟡

题目:给定一个不重复的整数数组 nums最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边子数组前缀上 构建左子树。
  3. 递归地在最大值 右边子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树

链接:最大二叉树

代码:

class Solution {
    /* 主函数 */
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return build(nums, 0, nums.length - 1);
    }

    /* 定义:将 nums[lo..hi] 构造成符合条件的树,返回根节点 */
    public TreeNode build(int[] nums, int lo, int hi) {
        if (lo > hi) {
            return null;
        }

        // 找到数组中的最大值和对应的索引
        int index = -1, maxVal = Integer.MIN_VALUE;
        for (int i = lo; i <= hi; i++) {
            if (maxVal < nums[i]) {
                index = i;
                maxVal = nums[i];
            }
        }

        TreeNode root = new TreeNode(maxVal);
        // 递归调用构造左右子树
        root.left = build(nums, lo, index - 1);
        root.right = build(nums, index + 1, hi);
        return root;
    }
}

21-617.合并二叉树🟢

题目:给你两棵二叉树: root1root2

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。注意: 合并过程必须从两个树的根节点开始。

链接:617. 合并二叉树

代码:

class Solution {  
    /* 主函数 */    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {  
        if (root1 == null) {  
            return root2;  
        }  
        if (root2 == null) {  
            return root1;  
        }  
        root1.val += root2.val;  
        root1.left = mergeTrees(root1.left, root2.left);  
        root1.right = mergeTrees(root1.right, root2.right);  
        return root1;  
    }  
}

4.二叉树公共祖先问题

26-236.二叉树的最近公共祖先🟡

题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

链接:236. 二叉树的最近公共祖先

代码:

class Solution {
    // 定义:输入三个参数 root,p,q,根据左右子树遍历结果返回一个节点
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 递归结束条件
        if (root == null || root == p || root == q) {
            return root;
        }

        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        // 情况 1
        if (left != null && right != null) {
            return root;
        }
        // 情况 2
        if (left == null && right == null) {
            return null;
        }
        // 情况 3
        return left == null ? right : left;
    }
}

28-235.二叉搜索树的最近公共祖先🟡

题目:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

链接:235. 二叉搜索树的最近公共祖先

代码:

1.递归解法

class Solution {
    // 一定能找到结果,所以不用判断节点为空返回的情况
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 如果当前节点比两个待查节点大,就往左子树找
        if (root.val > p.val && root.val > q.val) {
            return lowestCommonAncestor(root.left, p, q);
        }
        // 如果当前节点比两个待查节点小,就往右子树找
        if (root.val < p.val && root.val < q.val) {
            return lowestCommonAncestor(root.right, p, q);
        }
        return root;
    }
}

2.迭代解法

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while (true) {
            // 如果当前节点比两个待查节点大,就往左子树找
            if (root.val > p.val && root.val > q.val) {
                root = root.left;
                // 如果当前节点比两个待查节点小,就往右子树找
            } else if (root.val < p.val && root.val < q.val) {
                root = root.right;
                // 找到最终节点,跳出循环
            } else {
                break;
            }
        }
        return root;
    }
}

5.求二叉搜索树的属性

22-700.二叉搜索树中的搜索🟢

题目:给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null

链接:700. 二叉搜索树中的搜索

代码:

1.递归解法

class Solution {  
    public TreeNode searchBST(TreeNode root, int val) {  
        if (root == null || root.val == val) {  
            return root;  
        }  
        // 目标值小于当前值则去左子树搜索  
        if (val < root.val) {  
            return searchBST(root.left, val);  
        }  
        // 目标值大于当前值则去右子树搜索  
        if (val > root.val) {  
            return searchBST(root.right, val);  
        }  
        return root;  
    }  
}

2.迭代解法

class Solution {  
    // 利用二叉搜索树特点,优化,可以不需要栈  
    public TreeNode searchBST(TreeNode root, int val) {  
        while (root != null)  
            if (val < root.val) {  
                root = root.left;  
            } else if (val > root.val) {  
                root = root.right;  
            } else return root;  
        return null;  
    }  
}

23-98.验证二叉搜索树🟡

题目:给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

链接:98. 验证二叉搜索树

代码:

class Solution {  
    // 记录前一个节点的值  
    public long prev = Long.MIN_VALUE;  
    // 二叉搜索树中序遍历得到的是一个递增的序列,也可以用一个数组记录再判断数组是否递增  
    public boolean isValidBST(TreeNode root) {  
        if (root == null) {  
            return true;  
        }  
        if (!isValidBST(root.left)) {  
            return false;  
        }  
        // 当前节点小于等于前一个节点的值则不满足二叉搜索树条件  
        if (root.val <= prev) {  
            return false;  
        }  
        prev = root.val;  
        return isValidBST(root.right);  
    }  
}

24-530.二叉搜索树的最小绝对差🟢

题目:给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值

差值是一个正数,其数值等于两值之差的绝对值。

链接:530. 二叉搜索树的最小绝对差

代码:

class Solution {  
    TreeNode prev = null;  
    int res = Integer.MAX_VALUE;  
    public int getMinimumDifference(TreeNode root) {  
        traverse(root);  
        return res;  
    }  
  
    void traverse(TreeNode root) {  
        if (root == null) {  
            return;  
        }  
        traverse(root.left);  
        // 中序遍历位置  
        if (prev != null) {  
            // 记录最小值  
            res = Math.min(res, root.val - prev.val);  
        }  
        prev = root;
        traverse(root.right);  
    }  
}

25-501.二叉搜索树中的众数🟢

题目:给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

链接:501. 二叉搜索树中的众数

代码:

class Solution {  
    ArrayList<Integer> resList = new ArrayList<>();  
    public int maxCount = 0;  
    public int count = 0;  
    public TreeNode pre = null;  
  
    public int[] findMode(TreeNode root) {  
        traversal(root);
        // 将resList的元素拷贝到res数组中  
        int[] res = new int[resList.size()];  
        for (int i = 0; i < resList.size(); i++) {  
            res[i] = resList.get(i);  
        }  
        return res;  
    }  
  
    public void traversal(TreeNode root) {  
        if (root == null) {  
            return;  
        }  
        traversal(root.left);  
  
        // 计数  
        if (pre == null || root.val != pre.val) {  
            count = 1;  
        } else {  
            count++;  
        }  
        // 更新结果以及maxCount  
        if (count > maxCount) {  
            resList.clear();  
            resList.add(root.val);  
            maxCount = count;  
        } else if (count == maxCount) {  
            resList.add(root.val);  
        }  
        // 记录前一个节点  
        pre = root;  
  
        traversal(root.right);  
    }  
}

6.二叉搜索树的修改与构造

29-701.二叉搜索树中的插入操作🟡

题目:给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。

链接:701. 二叉搜索树中的插入操作

代码:

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        // 找到空位置返回待插入节点
        if (root == null) {
            return new TreeNode(val);
        }
        if (root.val < val) {
            // 插入节点操作,insertIntoBST函数返回值就是待插入节点
            root.right = insertIntoBST(root.right, val);
        }
        if (root.val > val) {
            root.left = insertIntoBST(root.left, val);
        }
        // 返回根节点给上一层
        return root;
    }
}

30-450.删除二叉搜索树中的节点🟡

题目:给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

链接:450. 删除二叉搜索树中的节点

代码:

1.代码随想录解法:左子树添加到右子树最左边,返回删除节点右孩子为新的当前根节点

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        //分为五种情况:
        // 1.未找到,直接返回root
        if (root == null) return root;
        if (root.val == key) {
            // 2.找到的节点左子树为空,右子树非空,右子树补上
            if (root.left == null && root.right != null) {
                return root.right;
                // 3.找到的节点右子树为空,左子树非空,左子树补上
            } else if (root.left != null && root.right == null) {
                return root.left;
                // 4.找到的节点左右子树都为空,直接删除
            } else if (root.left == null && root.right == null) {
                return null;
                // 5.找到的节点左右子树都非空,左子树添加到右子树最左边,
                // 返回删除节点右孩子为新的根节点
            } else {
                TreeNode node = root.right;
                while (node.left != null) {
                    node = node.left;
                }
                node.left = root.left;
                return root.right;
            }
        }
        if (root.val > key) root.left = deleteNode(root.left, key);
        if (root.val < key) root.right = deleteNode(root.right, key);
        return root;
    }
}

2.labuladong 解法:右子树最小节点替换待删节点,再把待删节点删了

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) return null;
        if (root.val == key) {
            // 这两个 if 把情况 1 和 2 都正确处理了
            if (root.left == null) return root.right;
            if (root.right == null) return root.left;
            // 处理情况 3
            // 获得右子树最小的节点
            TreeNode minNode = getMin(root.right);
            // 删除右子树最小的节点
            root.right = deleteNode(root.right, minNode.val);
            // 用右子树最小的节点替换 root 节点
            minNode.left = root.left;
            minNode.right = root.right;
            root = minNode;
        } else if (root.val > key) {
            root.left = deleteNode(root.left, key);
        } else if (root.val < key) {
            root.right = deleteNode(root.right, key);
        }
        return root;
    }

    TreeNode getMin(TreeNode node) {
        // BST 最左边的就是最小的
        while (node.left != null) node = node.left;
        return node;
    }
}

31-669.修剪二叉搜索树🟡

题目:给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

链接:669. 修剪二叉搜索树

代码:

class Solution {
    // 函数定义:满足区间返回root,不满足则返回root的符合条件的子节点
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) {
            return null;
        }
        if (root.val < low) {
            // 当前节点比low小那就去右边寻找符合区间[low, high]的节点
            return trimBST(root.right, low, high);
        }
        if (root.val > high) {
            return trimBST(root.left, low, high);
        }
        // root.left接入符合条件的左孩子
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);
        return root;
    }
}

32-108.将有序数组转换为二叉搜索树🟡

题目:给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。

链接:108. 将有序数组转换为二叉搜索树

代码:

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        TreeNode root = traversal(nums, 0, nums.length - 1);
        return root;
    }

    // 左闭右闭区间[left, right]
    // 函数定义:根据数组和给定区间构造root的左右节点
    private TreeNode traversal(int[] nums, int left, int right) {
        if (left > right) return null;

        int mid = left + ((right - left) >> 1); // 防止溢出
        TreeNode root = new TreeNode(nums[mid]);
        root.left = traversal(nums, left, mid - 1);
        root.right = traversal(nums, mid + 1, right);
        return root;
    }
}

33-538.把二叉搜索树转换为累加树🟡

题目:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

链接: 538. 把二叉搜索树转换为累加树

代码:

class Solution {
    public TreeNode convertBST(TreeNode root) {
        traverse(root);
        return root;
    }
    
    int sum = 0;

    // 右中左遍历,累加节点的值
    void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        traverse(root.right);
        // 维护累加和
        sum += root.val;
        // 将 BST 转化成累加树
        root.val = sum;
        traverse(root.left);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值