【LeetCode 每日一题】面试题 17.12. BiNode

Problem: 面试题 17.12. BiNode

文章目录

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

1. 整体思路

核心逻辑

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

    • 因为输入是二叉搜索树 (BST),通过中序遍历(左 -> 根 -> 右),我们可以按从小到大的顺序访问所有节点。
    • 这个顺序正是我们需要构建的链表的顺序。
  2. 链表构建 (Pointer Manipulation)

    • 使用一个哨兵节点(Dummy Head)head 来简化链表头部的处理。
    • 使用一个全局变量 pre 来记录中序遍历过程中上一个访问的节点
    • 在遍历到当前节点 node 时:
      • 将上一个节点 preright 指针指向当前节点 node(建立链表连接)。
      • 将当前节点 nodeleft 指针置空(题目要求)。
      • 更新 pre 为当前节点,以便处理下一个节点。
  3. 递归实现

    • 标准的递归 DFS 实现中序遍历:dfs(left) -> 处理当前 -> dfs(right)

2. 完整代码

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 {
    // 创建一个哨兵节点 head,它的值不重要 (-1)
    // 它的 right 指针将指向最终链表的头节点
    TreeNode head = new TreeNode(-1);
    
    // pre 用于记录中序遍历中的"前驱节点"
    // 初始为 null,或者也可以指向 head,取决于具体实现逻辑
    TreeNode pre = null;

    public TreeNode convertBiNode(TreeNode root) {
        // 开始中序遍历
        dfs(root);
        // 返回哨兵节点的右孩子,即链表的真正头节点
        return head.right;
    }

    // 中序遍历辅助函数
    private void dfs(TreeNode node) {
        // 递归终止条件:节点为空
        if (node == null) {
            return;
        }

        // 1. 递归处理左子树
        dfs(node.left);

        // 2. 处理当前节点 (核心链表构建逻辑)
        if (pre == null) {
            // 如果 pre 为空,说明当前 node 是中序遍历访问的第一个节点(整棵树最小的节点)
            // 它应该是链表的头,所以让 head.right 指向它
            // 同时初始化 pre 指向当前节点
            pre = node;
            head.right = node;
        } else {
            // 如果 pre 不为空,说明之前已经访问过节点
            // 将前驱节点 pre 的 right 指针指向当前节点 node,建立链表连接
            pre.right = node;
            // 更新 pre 指向当前节点,为下一次连接做准备
            pre = node;
        }
        
        // 题目要求:所有节点的 left 指针必须置为 null
        // 这一步非常重要,否则结果不是纯粹的单向链表,可能保留树的结构导致判题错误或循环引用
        node.left = null;

        // 3. 递归处理右子树
        dfs(node.right);
    }
}

3. 时空复杂度

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

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

  • 计算依据
    • 这是一个标准的深度优先搜索(DFS)遍历。
    • 每个节点被访问且仅被访问一次。
    • 在每个节点上的操作(修改指针、判断)都是 O ( 1 ) O(1) O(1) 的常数操作。
  • 结论 : O ( N ) O(N) O(N)。

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

  • 计算依据
    • 代码是就地修改(In-place)树的指针,没有创建新的节点列表。
    • 主要的额外空间消耗来自于递归调用栈
    • 递归深度取决于树的高度 H H H。
    • 最坏情况(退化为链表): O ( N ) O(N) O(N)。
    • 最好/平均情况(平衡树): O ( log ⁡ N ) O(\log N) O(logN)。
  • 结论 : O ( N ) O(N) O(N)(最坏情况)。
相关推荐
NAGNIP6 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱14 小时前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub17 小时前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub17 小时前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub18 小时前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub18 小时前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub18 小时前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉
NAGNIP1 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试
NAGNIP1 天前
一文搞懂激活函数!
算法·面试
董董灿是个攻城狮1 天前
AI 视觉连载7:传统 CV 之高斯滤波实战
算法