返回

剑指 Offer 06:从尾到头打印链表,逆向思维,简单实现

前端

导言

「剑指 Offer」系列是针对算法和数据结构的经典题目集,备受程序员推崇。其中,「从尾到头打印链表」问题(题目编号 06)考察了链表的基本操作和逆向思维的运用。本文将从递归和栈两个角度,深入探讨该问题的解题思路,帮助读者全面理解链表的特性和算法实现。

链表特点

链表是一种非连续存储的数据结构,由一个个独立的节点组成。每个节点包含两个部分:存储元素本身的「值」(value)和指向下一个节点的「指针」(next)。链表具有以下特点:

  • 节点之间通过指针连接,顺序访问复杂度为 O(n),其中 n 为节点数量。
  • 链表的插入和删除操作时间复杂度为 O(1),因为它只需要修改指针即可。
  • 链表的尾节点指针指向 null,表示链表的结束。

解题思路

递归解法

递归是一种函数自调用的技术,常用于解决分治问题。对于「从尾到头打印链表」问题,可以采用递归的方式从链表尾部依次打印元素。递归函数如下:

List<Integer> printListFromTail(ListNode head) {
    if (head == null) {
        return new ArrayList<>();
    }
    List<Integer> result = printListFromTail(head.next);
    result.add(head.val);
    return result;
}

步骤详解:

  • 如果链表为空,直接返回空列表。
  • 否则,调用递归函数打印链表的剩余部分,并将结果存储在 result 中。
  • 将链表头结点的值添加到 result 的末尾。
  • 返回 result 列表。

栈解法

栈是一种后进先出的数据结构,其特点是只能从栈顶添加或删除元素。对于「从尾到头打印链表」问题,可以利用栈的特性来实现逆序打印。具体实现如下:

List<Integer> printListFromTail(ListNode head) {
    Stack<Integer> stack = new Stack<>();
    ListNode cur = head;
    while (cur != null) {
        stack.push(cur.val);
        cur = cur.next;
    }
    List<Integer> result = new ArrayList<>();
    while (!stack.isEmpty()) {
        result.add(stack.pop());
    }
    return result;
}

步骤详解:

  • 创建一个栈并遍历链表,将每个节点的值压入栈中。
  • 然后依次从栈中弹出元素,并添加到 result 列表中。
  • 返回 result 列表。

总结

「从尾到头打印链表」问题考察了链表的基本操作和逆向思维的运用。通过递归和栈两种思路的深入剖析,本文清晰阐述了问题的解决过程。读者可以根据自己的理解,选择适合自己的解法。希望本文能够帮助大家更好地理解链表的特性和算法实现,从而提升编程能力。