【LeetCode 每日一题】1382. 将二叉搜索树变平衡——中序遍历 - 数组 - 平衡 BST

Problem: 1382. 将二叉搜索树变平衡

文章目录

  • [1. 整体思路](#1. 整体思路)
  • [2. 完整代码](#2. 完整代码)
  • [3. 时空复杂度](#3. 时空复杂度)
      • [时间复杂度: O ( N ) O(N) O(N)](#时间复杂度: O ( N ) O(N) O(N))
      • [空间复杂度: O ( N ) O(N) O(N)](#空间复杂度: O ( N ) O(N) O(N))

1. 整体思路

核心问题

我们需要将一棵可能高度不平衡 的二叉搜索树(BST),转换成一棵高度平衡的二叉搜索树。

算法逻辑

  1. 中序遍历 (In-order Traversal)

    • 二叉搜索树的特性 :通过中序遍历(左 -> 根 -> 右)可以得到一个升序的节点值序列。
    • 我们将原 BST 的所有节点值按照中序遍历的顺序存入一个 List<Integer> 中。
    • 这一步将树结构转化为了有序数组结构,消除了原本的树结构信息。
  2. 有序数组转平衡 BST (Reconstruction)

    • 这是一个经典问题(LeetCode 108. 将有序数组转换为二叉搜索树)。
    • 策略 :为了让生成的 BST 尽可能平衡,我们应该总是选择数组的中间元素作为根节点。
    • 这样,数组被均分为左右两半,左半部分构建左子树,右半部分构建右子树。
    • 这个过程递归进行,直到数组范围为空。
    • 由于每次都取中点,左右子树的高度差最多为 1,从而保证了结果是一棵高度平衡的 BST。

2. 完整代码

java 复制代码
import java.util.ArrayList;
import java.util.List;

/**
 * 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 TreeNode balanceBST(TreeNode root) {
        // 1. 中序遍历获取升序数组
        List<Integer> nums = inorderTraversal(root);
        // 2. 将有序数组转换为平衡二叉搜索树
        return sortedArrayToBST(nums);
    }

    // 中序遍历辅助方法
    private List<Integer> inorderTraversal(TreeNode node) {
        List<Integer> ans = new ArrayList<>();
        dfs(ans, node);
        return ans;
    }

    // DFS 实现中序遍历
    private void dfs(List<Integer> ans, TreeNode node) {
        if (node == null) {
            return;
        }
        dfs(ans, node.left);
        ans.add(node.val);
        dfs(ans, node.right);
    }

    // 重建平衡 BST 入口
    private TreeNode sortedArrayToBST(List<Integer> nums) {
        // 这里的 range 是 [left, right) 左闭右开区间
        return buildBST(nums, 0, nums.size());
    }

    // 递归构建平衡 BST
    // left: 当前处理范围的起始索引 (inclusive)
    // right: 当前处理范围的结束索引 (exclusive)
    private TreeNode buildBST(List<Integer> nums, int left, int right) {
        // 递归终止条件:区间为空
        if (left == right) {
            return null;
        }
        
        // 取中间元素作为根节点
        // >>> 1 是无符号右移,相当于除以 2,但在处理负数时更安全(虽然这里索引是非负的)
        int m = (left + right) >>> 1;
        
        // 创建新节点,值为中间元素
        // 递归构建左子树:范围 [left, m)
        // 递归构建右子树:范围 [m + 1, right)
        return new TreeNode(nums.get(m), buildBST(nums, left, m), buildBST(nums, m + 1, right));
    }
}

3. 时空复杂度

假设二叉树的节点总数为 N N N。

时间复杂度: O ( N ) O(N) O(N)

  1. 中序遍历 :访问每个节点一次,耗时 O ( N ) O(N) O(N)。
  2. 重建 BST
    • 构建过程本质上也是对每个节点访问一次(每次递归创建一个新节点)。
    • 总共有 N N N 个节点需要创建。
    • 虽然 buildBST 是递归调用的,但总的节点创建操作是线性的。
    • 耗时 O ( N ) O(N) O(N)。
  • 总计 : O ( N ) + O ( N ) = O ( N ) O(N) + O(N) = O(N) O(N)+O(N)=O(N)。

空间复杂度: O ( N ) O(N) O(N)

  1. 有序列表 nums :我们需要一个长度为 N N N 的 ArrayList 来存储节点值,空间 O ( N ) O(N) O(N)。
  2. 递归栈空间
    • 中序遍历时,最坏情况(斜树)栈深度为 N N N。
    • 重建 BST 时,树是平衡的,栈深度为 log ⁡ N \log N logN。
    • 取最大值,空间复杂度为 O ( N ) O(N) O(N)。
  • 结论 : O ( N ) O(N) O(N)。
相关推荐
CoovallyAIHub2 小时前
Moonshine:比 Whisper 快 100 倍的端侧语音识别神器,Star 6.6K!
深度学习·算法·计算机视觉
CoovallyAIHub3 小时前
速度暴涨10倍、成本暴降6倍!Mercury 2用扩散取代自回归,重新定义LLM推理速度
深度学习·算法·计算机视觉
CoovallyAIHub3 小时前
实时视觉AI智能体框架来了!Vision Agents 狂揽7K Star,延迟低至30ms,YOLO+Gemini实时联动!
算法·架构·github
CoovallyAIHub4 小时前
开源:YOLO最强对手?D-FINE目标检测与实例分割框架深度解析
人工智能·算法·github
CoovallyAIHub4 小时前
OpenClaw:从“19万星标”到“行业封杀”,这只“赛博龙虾”究竟触动了谁的神经?
算法·架构·github
刀法如飞4 小时前
程序员必须知道的核心算法思想
算法·编程开发·算法思想
徐小夕5 小时前
pxcharts Ultra V2.3更新:多维表一键导出 PDF,渲染兼容性拉满!
vue.js·算法·github
CoovallyAIHub6 小时前
OpenClaw一脚踩碎传统CV?机器终于不再只是看世界
深度学习·算法·计算机视觉
CoovallyAIHub7 小时前
仅凭单目相机实现3D锥桶定位?UNet-RKNet破解自动驾驶锥桶检测难题
深度学习·算法·计算机视觉
zone77397 小时前
002:RAG 入门-LangChain 读取文本
后端·算法·面试