【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)(最坏情况)。
相关推荐
To_OC5 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
旖-旎6 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC7 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
delishcomcn8 小时前
AI视觉识别+分切算法:电化铝缺陷检测与裁切一体化解锁
人工智能·算法
触底反弹8 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
雪碧聊技术8 小时前
力扣 LCR 091. 粉刷房子 —— 动态规划入门详解
算法·动态规划
CV-Climber11 小时前
检索技术的实际应用
人工智能·算法
hhzz12 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
从零开始的代码生活_12 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法