在 Kotlin 中实现 LeetCode 116 非常直观,因为 Kotlin/JVM 具有垃圾回收机制,不需要像 Rust 那样处理所有权,直接像 Python 一样操作对象引用即可,同时享受空安全(Null Safety)带来的编译期检查。
以下提供 迭代法 和 递归法 两种 Kotlin 实现。
前置:LeetCode 中的 Node 定义
(LeetCode 已内置,无需提交)
class Node(varval: Int) {
var left: Node? = null
var right: Node? = null
var next: Node? = null
}
方法一:迭代法(O(1) 空间,推荐)
利用上一层已经连接好的
“next” 指针,横向遍历并连接下一层的子节点。
class Solution {
fun connect(root: Node?): Node? {
if (root == null) return null
// leftmost 指向每一层的最左节点 var leftmost: Node? = root // 只要当前层不是叶子层(即还有下一层) while (leftmost?.left != null) { // head 用于遍历当前层的节点 var head: Node? = leftmost while (head != null) { // 1. 同一个父节点:左孩子 -> 右孩子 head.left!!.next = head.right // 2. 不同父节点:右孩子 -> 下一个节点的左孩子 if (head.next != null) { head.right!!.next = head.next!!.left } // 沿着 next 指针移动到当前层下一个节点 head = head.next } // 进入下一层(最左边的节点) leftmost = leftmost.left } return root }}
方法二:递归法(简洁直观)
利用递归栈隐式完成层序遍历,代码更短。
class Solution {
fun connect(root: Node?): Node? {
if (root?.left != null) {
// 左孩子指向右孩子
root.left!!.next = root.right
// 如果当前节点有 next,右孩子指向下一个节点的左孩子 if (root.next != null) { root.right!!.next = root.next!!.left } // 递归处理左右子树 connect(root.left) connect(root.right) } return root }}
Kotlin 实现要点解析
空安全操作符:
“?.”:安全调用,如果对象为
“null” 则返回
“null” 而不抛异常(如
“leftmost?.left != null”)。
“!!”:非空断言,在逻辑上已经确定不为
“null” 时使用(如
“head.left!!”),相当于告诉编译器“相信我,这里不是 null”。
“var head: Node? = leftmost”:声明可空的变量,方便在
“while” 循环中修改引用。
2. 无所有权负担:与 Rust 不同,Kotlin 中直接通过
“.next =” 赋值即可修改指针,不需要
“borrow_mut” 或
“Rc::clone”,写起来和 Python 一样简洁。
3. 尾递归优化:虽然递归解法没有显式加
“tailrec”(因为有两个递归调用,不是尾递归),但 Kotlin/JVM 的栈深度对于 O(\log N) 的完美二叉树完全足够。
复杂度分析
- 时间复杂度:O(N),每个节点仅访问一次。
- 空间复杂度:
- 迭代法:O(1),只使用固定数量的指针。
- 递归法:O(log N),递归调用栈的深度(树的高度)。
你可以直接把
“class Solution” 里的代码复制到 LeetCode Kotlin 编辑器提交。😊
需要我帮你把这段代码改成 LeetCode 117(普通二叉树) 的 Kotlin 版本,或者对比一下 Kotlin 和 Rust 实现上的核心差异 吗?