返回

算法基础入门-LeetCode-206.反转链表

前端

在算法学习的初期,我们经常会遇到一个看似简单却蕴含着不少技巧的问题——反转链表。这个问题不仅是链表操作的基础,更是理解指针操作和递归思想的绝佳案例。 很多初学者在面对这个问题时,可能会感到有些困惑,不知道该如何下手。别担心,接下来我们会一步步解析反转链表的思路,并用通俗易懂的语言和代码示例来帮助你彻底掌握它。

链表作为一种重要的数据结构,在实际应用中十分广泛。它不像数组那样需要连续的内存空间,而是通过指针将一个个节点连接起来,形成一个链式结构。每个节点通常包含两部分:数据域和指针域。数据域存储节点的值,而指针域则指向下一个节点的地址。

反转链表,顾名思义,就是将链表中节点的顺序翻转过来。举个例子,如果原本的链表是 1 -> 2 -> 3 -> 4 -> 5,那么反转后就变成了 5 -> 4 -> 3 -> 2 -> 1。

那么,我们该如何实现链表的反转呢?

一种常用的方法是迭代法。我们可以设置三个指针:prev、curr 和 next。prev 指向前一个节点,curr 指向当前节点,next 指向下一个节点。

初始状态下,prev 指向 None,curr 指向链表的头节点,next 指向 curr 的下一个节点。

然后,我们开始循环遍历链表。在每次循环中,我们需要进行以下操作:

  1. 将 curr 的 next 指针指向 prev,也就是将当前节点的指针指向前一个节点。
  2. 将 prev 指针移动到 curr,也就是将前一个节点指针后移。
  3. 将 curr 指针移动到 next,也就是将当前节点指针后移。
  4. 将 next 指针移动到 curr 的下一个节点,也就是将下一个节点指针后移。

重复以上步骤,直到 curr 指针为空,也就是遍历完整个链表。最后,prev 指针就指向了反转后链表的头节点。

下面是用 Python 代码实现的迭代法反转链表:

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reverseList(head):
    prev = None
    curr = head
    while curr:
        next = curr.next  # 保存下一个节点
        curr.next = prev  # 反转指针
        prev = curr  # 前一个节点后移
        curr = next  # 当前节点后移
    return prev  # 返回新的头节点

除了迭代法,我们还可以使用递归的方法来反转链表。递归的思路是:先反转链表的剩余部分,然后将当前节点连接到反转后的链表的尾部。

下面是用 Python 代码实现的递归法反转链表:

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reverseList(head):
    if not head or not head.next:  # 递归终止条件:空链表或只有一个节点
        return head
    new_head = reverseList(head.next)  # 反转剩余部分
    head.next.next = head  # 将当前节点连接到反转后的链表尾部
    head.next = None  # 断开当前节点与后续节点的连接
    return new_head  # 返回新的头节点

无论是迭代法还是递归法,它们的核心思想都是改变节点的指针指向,从而实现链表的反转。

常见问题解答

1. 反转链表的时间复杂度是多少?

答:无论是迭代法还是递归法,反转链表的时间复杂度都是 O(n),其中 n 是链表的长度。因为我们需要遍历一遍链表中的所有节点。

2. 反转链表的空间复杂度是多少?

答:迭代法的空间复杂度是 O(1),因为它只使用了几个额外的指针变量。递归法的空间复杂度是 O(n),因为递归调用会占用栈空间,而栈的深度最大为链表的长度 n。

3. 反转链表需要注意哪些边界条件?

答:需要注意空链表和只有一个节点的情况。在这两种情况下,链表不需要反转,直接返回原链表即可。

4. 反转链表在实际应用中有哪些场景?

答:反转链表在很多算法和数据结构中都有应用,例如:

  • 检测链表是否有环
  • 合并两个有序链表
  • 查找链表的倒数第 k 个节点

5. 如何调试反转链表的代码?

答:可以使用打印语句或者调试工具来跟踪代码的执行过程,观察指针的变化情况,从而找出代码中的错误。

希望通过本文的讲解,你对反转链表有了更深入的理解,并能够熟练地运用迭代法和递归法来解决这个问题。反转链表是算法学习中的一个重要基础,掌握它对你后续学习其他算法和数据结构会有很大的帮助。