给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
思路应该清晰:找到左右边界,切断形成子链表,反转该区间的子链表,与原始链表进行链接。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
# 使用遍历的方式,反转链表的函数,将当前节点和前一个节点进行反转
def reverse(head):
# 初始化第一个节点为空
pre = None
# 初始化当前节点为头节点
curr = head
# 当当前节点非空
while curr:
# 临时变量存储当前节点的指针
temp = curr.next
# 将当前节点的指针指向前一个节点
curr.next = pre
# 将当前节点作为前一个节点
pre = curr
# 将当前节点的指针作为当前节点。也就是顺延
curr = temp
# 创建一个虚拟头节点,这样对于left=1的情况也能统一处理
dummy = ListNode(0)
dummy.next = head # 指向头节点
pre = dummy # 作为最初的前一个节点
# 找到左边界限的前一个节点,也就是往后查看left-1次
for _ in range(left-1):
pre = pre.next
# 初始化右边界节点,不断往右走,直到到达右边的界限
right_node = pre
for _ in range(right-left+1):
right_node = right_node.next
# 切出区间链表
# 左边的节点
left_node = pre.next
# 右边的节点的下一个,为了定位最后的剩余区间
curr = right_node.next
# 切断原来的链表
pre.next = None # 修改链表的左边的节点的前一个节点的指针为空
right_node.next = None # 修改链表的右边的节点的指针为空
# 反转区间链表,前面已经将区间链表最右边的指针更换为空,所以只会反转该区间
reverse(left_node)
# 接回原来的链表
# 修改链表的左边的节点的前一个节点的指针为区间链表的右边节点
pre.next = right_node
# 此时的left_node已经是反转到右边了,所以将其指针指向剩余的右边区间
left_node.next = curr
# 返回头节点
return dummy.next
我们要做的事情 这段代码的目的是反转一个链表中从位置left到位置right之间的部分。链表是一种数据结构,每个元素都是一个节点,每个节点都有一个值和一个指向下一个节点的指针。如果没有下一个节点,这个指针就是空的。
怎么做呢?
准备阶段: 首先,我们创建了一个假的"头节点"(我们叫它
dummy
),它的下一个节点指向真正的头节点。这样做的原因是为了方便处理当left等于1,也就是要反转的部分包括了链表的第一个节点的情况。找到要反转的部分: 然后,我们找到了要反转的部分的前一个节点和最后一个节点。这是通过移动指针完成的:从假的"头节点"开始,往右移动直到到达left的前一个位置,记下这个位置;然后,从这个位置再往右移动直到到达right的位置。
切断要反转的部分: 接下来,我们把要反转的部分从链表中"切出来"。我们让左边界的前一个节点的
next
指针指向None
,右边界节点的next
指针也指向None
。这样,我们就有了一个独立的链表段,只包含要反转的部分。反转: 现在,我们使用一个特别的函数
reverse
来反转这个独立的链表段。这个函数通过不断地改变节点的next
指针,让它们指向前一个节点,来达到反转的目的。接回原链表: 反转完成后,我们把反转的链表段接回原来的链表中。这是通过修改原来左边界的前一个节点的
next
指针,让它指向反转后的第一个节点(也就是原来的右边界节点),同时让原来的左边界节点(现在在反转段的末尾)的next
指针指向剩下的链表部分来完成的。完成! 最后,我们返回假的"头节点"的下一个节点作为新的头节点,因为可能头节点也参与了反转。