题目:

        给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

示例 1:

img

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]

提示:

  • 链表中节点数目为 n

  • 1 <= n <= 500

  • -500 <= Node.val <= 500

  • 1 <= left <= right <= n


思路如下:

        这道题是链表反转的进阶版,只要求反转链表内部的一段链表,反转完成后再与为反转链表部分连接。因此首先要确定反转链表的头 leftright 位置,这里引用虚拟节点 dummy = ListNode(0) ,设定在头节点时 count = 1,找到 left 的前一个节点 pre,则 pre.next 就是 left 的位置。

        当 count 记数值等于 left 节点值时,设定第一个反转节点位置指针为 cur ,反转结束后的尾节点 tail 也在此。设定 cur 节点的后一个节点指针为 nxt ,反转开始。第一次反转,将 cur.next 指向 pre.next 为自身,因此跳过。第二次循环,cur 指向 nxt 的位置,进行题解代码的操作......直到最后 count <= right,返回头节点。


题解如下:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:zj
    def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
        count = 1
        dummy = ListNode(0)
        dummy.next = head
        pre = dummy
​
        # 未开始反转,寻找反转节点前的位置
        while pre.next and count < left:
            pre = pre.next
            count += 1
​
        cur = pre.next
        tail = cur
​
        while cur and count <= right:
            nxt = cur.next
​
            # 反转开始节点即是 cur 也是 tail,所以反转后仍是自己
            # cur 右移一步后开始反转
            cur.next = pre.next # cur 的 next 指针指向 pre 的 next
            pre.next = cur # pre 连接原来 tail 的指针断开 指向 cur
            tail.next = nxt # 原来 tail 的指针指向 nxt
            # cur 指向 nxt 的位置
            cur = nxt
            count += 1
            
        return dummy.next

题解示例:


假设链表为 1->2->3->4->5->NULL,left = 2,right = 4:

初始状态:
dummy 指向虚拟头节点,dummy.next 指向节点 1。
pre 移动到节点 1,count 增加到 2。

反转指定区间内的节点:
初始化 cur 为节点 2,tail 为节点 2。

第一次循环(count = 2):
nxt 指向节点 3。
cur.next 指向 pre.next(节点 1 的 next 是节点 2,所以 cur.next 指向节点 2,形成循环)。
pre.next 更新为 cur(节点 2),形成循环。
tail.next 指向 nxt(节点 3),保持剩余链表的连接。
cur 移动到 nxt(节点 3),count 增加到 3。

第二次循环(count = 3):
cur 指向节点 3。
nxt 指向节点 4。
cur.next 指向 pre.next(节点 2),将节点 3 插入到节点 2 后面。
pre.next 断开与节点 2 的连接,更新为 cur(节点 3)。
此时节点 2 tail.next 指向 nxt(节点 4),保持剩余链表的连接。
cur 移动到 nxt(节点 4),count 增加到 4。

第三次循环(count = 4):
nxt 指向节点 5。
cur.next 指向 pre.next(节点 3),将节点 4 插入到节点 3 后面。
pre.next 更新为 cur(节点 4)。
tail.next 指向 nxt(节点 5),保持剩余链表的连接。
cur 移动到 nxt(节点 5),count 增加到 5,循环结束。

最终状态:
pre.next 指向节点 4,tail.next 指向节点 5。
链表结构为 1->4->3->2->5->NULL。


逻辑梳理:

  1. 初始化计数器和虚拟头节点

    • count = 1:用于记录当前节点的位置。

    • dummy = ListNode(0):创建一个虚拟头节点,其 next 指向原链表的头节点。这有助于简化对头节点的处理。

    • pre = dummypre 指针初始化为虚拟头节点。

  2. 找到反转部分的前一个节点

    • 使用 while 循环将 pre 指针移动到反转部分的前一个节点。例如,当 left = 2 时,pre 会移动到节点 1

  3. 初始化指针

    • cur = pre.nextcur 指针初始化为反转部分的第一个节点。

    • tail = curtail 指针初始化为反转部分的第一个节点,用于后续连接剩余链表。

  4. 反转指定区间内的节点

    • 使用 while 循环逐步反转链表的指定部分。

    • nxt = cur.next:保存当前节点的下一个节点,避免断链。

    • cur.next = pre.next:将当前节点的 next 指针指向 pre.next,实现当前节点的反转。

    • pre.next = cur:将当前节点插入到 pre 指针之后。

    • tail.next = nxt:更新 tail 指针的 next,保持剩余链表的连接。

    • 移动 cur 指针到下一个需要处理的节点,并更新计数器。

  5. 返回结果

    • 最终返回 dummy.next,即反转后的链表头节点。

更多推荐