📜  反转链表的子列表(1)

📅  最后修改于: 2023-12-03 15:22:54.687000             🧑  作者: Mango

反转链表的子列表

在反转链表时,我们可以对整个链表进行反转,也可以对链表的子列表进行反转。本文将介绍反转链表的子列表的实现方法。

方法一:迭代法

我们可以遍历链表,找到需要反转的子链表,并对其进行反转。具体步骤如下:

  1. 找到需要反转的子链表的前一个节点。
  2. 定义一个指针 cur 指向子链表的第一个节点,将其作为反转后的头结点。
  3. 定义一个指针 pre 指向 cur 的前一个节点,将其作为反转后的尾结点。
  4. cur 指向下一个节点,并将 pre 指向 cur 的前一个节点,然后将 curnext 指向 pre
  5. 重复上一步操作,直到 cur 到达子链表的最后一个节点。
  6. 将子链表的前一个节点的 next 指向反转后的头结点,将反转后的尾结点的 next 指向子链表的后一个节点。

下面是迭代法的实现代码:

def reverse_between(head: ListNode, m: int, n: int) -> ListNode:
    if not head:
        return None
    
    # 定义虚拟节点,避免链表为空或需要反转的子链表从第一个节点开始时出现问题
    dummy = ListNode(-1)
    dummy.next = head
    
    # 找到需要反转的子链表的前一个节点
    pre = dummy
    for i in range(m - 1):
        pre = pre.next
        
    cur = pre.next  # 将 cur 指向子链表的第一个节点
    for i in range(n - m):
        nxt = cur.next  # 保存 cur 的下一个节点
        cur.next = nxt.next  # 将 cur 的 next 指向 nxt 的下一个节点
        nxt.next = pre.next  # 将 nxt 的 next 指向 pre 的下一个节点
        pre.next = nxt  # 将 pre 的 next 指向 nxt
    return dummy.next

时间复杂度为 $O(n)$,其中 $n$ 为链表长度。

方法二:递归法

我们可以使用递归法对子链表进行反转。具体步骤如下:

  1. 如果需要反转的子链表长度为 $1$,那么返回该节点。
  2. 定义一个指针 tail 指向子链表的后一个节点。
  3. 定义一个指针 new_head 递归反转下一层子链表,其值为反转后的头结点。
  4. 反转该层子链表:将该层子链表的第一个节点的 next 指向 tail,将 new_headnext 指向该层子链表的最后一个节点。
  5. 返回反转后的头结点。

下面是递归法的实现代码:

def reverse_between(head: ListNode, m: int, n: int) -> ListNode:
    if not head or m == n:
        return head

    # 将 head 的 next 指向反转后的子链表
    if m == 1:
        return reverse(head, n - m + 1)
    head.next = reverse_between(head.next, m - 1, n - 1)
    return head

def reverse(head: ListNode, n: int) -> ListNode:
    if n == 1:
        return head
    
    tail = head.next
    new_head = reverse(head.next, n - 1)
    head.next = tail.next
    tail.next = head
    return new_head

时间复杂度为 $O(n)$,其中 $n$ 为链表长度。

以上是本文介绍的反转链表的子列表的实现方法,希望能对您有所帮助。