翻转二叉树(镜像)
Invert Binary Tree (Mirror)
开始编码给一棵嵌套字典表示的二叉树,每个节点形如 {"value": v, "left": L, "right": R},其中 L、R 自身也是树(或 None 表示「没有孩子」)。请返回翻转后的(镜像)树:在每个节点上交换它的左右子树。这就是经典的 LeetCode 226。输出必须是一棵全新的、结构已交换好的树;节点 value 原样保留。
递归解只有三行:tree is None 时返回 None,否则递归两个孩子拿到翻转后的两个子树,再返回一个 left 和 right 已交换的新节点。镜像是个结构性变换——它从不读也从不改任何节点的 value,只调整父子之间的连线。时间复杂度 O(n_nodes)(每个节点恰好访问一次),空间 O(tree_height) 用于递归栈。
Examples
solution({"value": 4, "left": {"value": 2, "left": {"value": 1, ...}, "right": {"value": 3, ...}}, "right": {"value": 7, "left": {"value": 6, ...}, "right": {"value": 9, ...}}}) 返回 {"value": 4, "left": {"value": 7, "left": {"value": 9, ...}, "right": {"value": 6, ...}}, "right": {"value": 2, "left": {"value": 3, ...}, "right": {"value": 1, ...}}}。根 4 不动。原本的左子树(根 2、叶子 1 和 3)和右子树(根 7、叶子 6 和 9)整体互换位置,每个子树内部的两个叶子也互换。这是 LeetCode 226 的原题示例。
solution({"value": 7, "left": null, "right": null}) 返回 {"value": 7, "left": null, "right": null}。单叶节点没有孩子可以交换,交换两个 None 还是两个 None,输出结构上和输入完全相同。
solution(None) 返回 None。空树是递归基底。如果不写这一支,第一次访问 tree["left"] 就会立刻抛 TypeError: 'NoneType' is not subscriptable。
签名见 stubs/stub.py。
Practical context
树的镜像操作出现在任何需要把递归结构「翻转方向」的场景里。在格子树期权定价(二叉/三叉模型)中,把资产价格树关于初始节点做反射,相当于把每一步的「上涨」和「下跌」互换——得到的镜像树会用「时间反演」动力学给同一份期权定价,这是在 Cox–Ross–Rubinstein 格子上做反向归纳健壮性检查、以及验证看涨–看跌对称性的核心套路。在决策树概率题里,把场景树镜像一下就等价于把每个二元结果的标签互换(正面 ↔ 反面、成功 ↔ 失败),这是「把贝叶斯后验树看成对偶事件标签下的版本」最干净的写法——比较一棵后验树和它「补事件」孪生树时非常好用。在强化学习里的对称两人零和博弈树(如国际象棋局面评估、交替走子的 Minimax)中,镜像操作把「白方视角下的局面」映成「黑方视角下的同一局面」,于是单一一份学到的价值函数可以在两个玩家视角间复用。这个模式还出现在表达式树代数恒等变换(在每个交换运算符上交换左右操作数实现交换律重写)以及双向图算法(把树状有向图镜像就是把所有边反向)里。能解 LeetCode 226 的那三行递归,就是上面所有这些场景背后的同一台引擎。
约束条件
- 0 ≤ 树大小 ≤ 10^4 个节点
- 树深度 ≤ 1000
- 每个节点是字典 {value, left, right};left/right 自身也是树或 null
- 节点值可以是任意可哈希类型(int、float、str 等)
- 空树用 None / null 表示
样例
Case 1 · empty tree returns empty
输入: [null]
期望: null
空树(None)翻转后还是空树。这是递归基底:函数第一行必须先判 `tree is None`,否则后面访问 `tree["left"]` 会立刻报 KeyError/TypeError。
Case 2 · single node unchanged
输入: [{"value":7,"left":null,"right":null}]
期望: {"value":7,"left":null,"right":null}
单节点没有左右子树(都是 None),交换两个 None 还是两个 None,节点值保持不变。这道题钉死「叶子翻转后等于自己」的约定。
Case 3 · LeetCode 226 canonical example
输入: [{"value":4,"left":{"value":2,"left":{"value":1,"left":null,"right":null},"right":{"value":3,"left":null,"right":null}},"right":{"value":7,"left":{"value":6,"left":null,"right":null},"right":{"value":9,"left":null,"right":null}}}]
期望: {"value":4,"left":{"value":7,"left":{"value":9,"left":null,"right":null},"right":{"value":6,"left":null,"right":null}},"right":{"value":2,"left":{"value":3,"left":null,"right":null},"right":{"value":1,"left":null,"right":null}}}
LeetCode 226 原题示例:原树根 4,左子树 [2,1,3]、右子树 [7,6,9]。翻转后根仍为 4,但左右子树整体互换,并且每个子树内部也镜像了——左变 [7,9,6]、右变 [2,3,1]。每一层都做了交换。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · empty tree returns empty
输入: [null]
期望: null
空树(None)翻转后还是空树。这是递归基底:函数第一行必须先判 `tree is None`,否则后面访问 `tree["left"]` 会立刻报 KeyError/TypeError。
Case 2 · single node unchanged
输入: [{"value":7,"left":null,"right":null}]
期望: {"value":7,"left":null,"right":null}
单节点没有左右子树(都是 None),交换两个 None 还是两个 None,节点值保持不变。这道题钉死「叶子翻转后等于自己」的约定。
Case 3 · LeetCode 226 canonical example
输入: [{"value":4,"left":{"value":2,"left":{"value":1,"left":null,"right":null},"right":{"value":3,"left":null,"right":null}},"right":{"value":7,"left":{"value":6,"left":null,"right":null},"right":{"value":9,"left":null,"right":null}}}]
期望: {"value":4,"left":{"value":7,"left":{"value":9,"left":null,"right":null},"right":{"value":6,"left":null,"right":null}},"right":{"value":2,"left":{"value":3,"left":null,"right":null},"right":{"value":1,"left":null,"right":null}}}
LeetCode 226 原题示例:原树根 4,左子树 [2,1,3]、右子树 [7,6,9]。翻转后根仍为 4,但左右子树整体互换,并且每个子树内部也镜像了——左变 [7,9,6]、右变 [2,3,1]。每一层都做了交换。