Java剑指Offer精讲:链表反转、回文检测与二叉树展开实战

听雨眠
听雨眠
发布时间:2026-10-16| 5人浏览过
原创

针对《剑指Offer》中的经典链表与二叉树题目,本文详细拆解了迭代法反转链表、递归实现K组翻转、利用后序遍历判断回文链表,以及二叉树的镜像翻转、层级节点连接与线性化展开等六大核心算法的Java实现逻辑与代码。

单链表的完全反转

处理链表问题时,最基础且高频的操作是将链表进行原地反转。该操作通常采用迭代方式,通过维护三个指针来实现节点的重新指向,避免内存空间的额外浪费。操作时需注意边界条件,如链表为空或仅有一个节点时的直接返回。

在 Java 中,我们定义 Solution 类来实现这一逻辑。使用 pre 记录前驱节点,cur 作为当前移动节点,nxt 暂存后继节点以防止断链。循环直到 cur 为空,最终返回新的头节点 pre。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

K个一组链表翻转

当需要对链表进行分组反转时,需先统计剩余节点数量是否满足组数要求。如果不满足,则保留原有顺序;如果满足,则对该组进行局部反转,并将前一组的尾节点连接到反转后的新头部。

该方法利用了递归思想。首先通过快指针 b 向前移动 k 步来确认区间,若中途为空则说明剩余不足 k 个,直接返回。随后调用辅助方法 reverse(a, b) 完成局部反转,并通过递归调用处理后续节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
         if (head == null) return null;
         ListNode a = head, b = head;
         for (int i = 0; i < k; i++) {
            if (b == null) return head;
             b = b.next;
         }
         ListNode newHead = reverse(a, b);
         a.next = reverseKGroup(b, k);
         return newHead;
    }
    
    private ListNode reverse(ListNode a, ListNode b) {
        ListNode pre = null;
        ListNode cur = a;
        while(cur != b){
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

基于后序遍历的回文链表判定

判断链表是否为回文结构,除了双指针法外,还可以利用递归的后序遍历特性。由于递归调用栈天然具备“后进先出”的特性,当递归到达链表末尾开始回溯时,实际上是从后往前访问节点,这与从前往后的外层变量形成了对比。

我们在 Solution 中设置一个实例变量 left 初始化为头节点。traverse 方法负责递归至尾部,并在回溯过程中比较 right(当前栈帧节点)与 left 的值,同时推进 left 指针。只有所有对应位置相等,才返回真值。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    ListNode left;
    public boolean isPalindrome(ListNode head) {
        left = head;
        return traverse(head);
    }
    
    private boolean traverse(ListNode right){
        if (right == null) return true;
        boolean res = traverse(right.next);
        res = res && (right.val == left.val);
        left = left.next;
        return res;
    }
}

二叉树的镜像翻转

翻转二叉树是递归应用的典型场景。核心逻辑是将根节点的左子树与右子树互换,然后递归地对左右子树执行相同的操作,直至叶子节点。

在代码实现中,当遇到空节点时直接返回 null。否则,分别递归获取翻转后的左子树 lf 和右子树 rg,然后将 root.left 指向 rg,root.right 指向 lf,最后返回 root 即可。

/**
 * 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 invertTree(TreeNode root) {
        if(root==null){
            return null;
        }
        TreeNode lf = invertTree(root.left);
        TreeNode rg = invertTree(root.right);
        root.left = rg;
        root.right = lf;
        return root;
    }
}

完美二叉树的节点右侧连接

对于完美二叉树(Perfect Binary Tree),每个节点都有两个子节点,且所有叶子在同一层。任务是让每个节点的 next 指针指向其同层的下一个右侧节点。

我们可以编写一个辅助函数 method(left, right),它负责处理父节点的两个孩子 left 和 right 之间的连线。逻辑包括:
1. 将 left.next 指向 right。
2. 递归连接 left 的内部子节点。
3. 递归连接 right 的内部子节点。
4. 递归跨越连接 left 的右子节点与 right 的左子节点(这是跨树边连接的关键)。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;
    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }
    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/
 
class Solution {
    public Node connect(Node root) {
        if(root==null) return null;
        method(root.left, root.right);
        return root;
    }
    
    private void method(Node left, Node right){
        if (left == null || right == null) {
            return;
        }
        left.next = right;
        method(left.left, left.right);
        method(right.left, right.right);
        method(left.right, right.left);
    }
}

二叉树转化为展开链表

将二叉树“展开”为单链表,意味着在保持某种遍历顺序(通常是前序遍历)的前提下,使所有节点的 left 指针为 null,right 指针指向下一个节点。

算法采用自底向上的递归策略。首先递归处理左子树和右子树。此时,左子树和右子树都已经处理成链表形态。接下来,将根的左子树整体移动到根的右边(即 root.right = left,并断开原 left 链接)。找到处理后链表的最末端节点 p,将其 right 指向原来的右子树链表头。这样就实现了按顺序合并。

/**
 * 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 void flatten(TreeNode root) {
        if (root == null) return;
 
        flatten(root.left);
        flatten(root.right);
 
        TreeNode left = root.left;
        TreeNode right = root.right;
 
        root.left = null;
        root.right = left;
 
        TreeNode p = root;
        while (p.right != null) {
            p = p.right;
        }
        p.right = right;
    }
}
以上就是剑指Offer之Java算法习题精讲链表与二叉树专项训练的详细内容,更多关于Java 链表的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。