反转链表II
分析
遍历一次先找到left的前一个节点pre,再找到right的后一个节点succ 我们只对left - right 中间的链表进行翻转操作【leetcode 206题】,然后重新把pre.next=right left.next=succ连接回去
多画画方便理解:
翻转单链表操作(迭代法)
def reverseList(self, head: ListNode) -> ListNode:
prev, curr = None, head
while curr is not None:
next = curr.next
curr.next = prev
prev = curr
curr = next
return prev#最后prev移动到最后一个节点,作为头结点
理解:
翻转单链表操作(递归法 难理解)
def reverseList(self, head: ListNode) -> ListNode:
if head is None or head.next is None:#递归终止条件,最小子问题,递的过程
return head
p = self.reverseList(head.next)#递归调用
head.next.next = head#归的过程,做一个翻转的动作
head.next = None
return p
虚拟头结点的定义
因为我们这里是翻转子区间,而不一定是整个链表,方便操作
# 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
dummy_node = ListNode(-1)
dummy_node.next = head
代码
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
def reverse_linked_list(head: ListNode):
# 也可以使用递归反转一个链表
pre = None
cur = head
while cur:
next = cur.next#临时存放
cur.next = pre
pre = cur
cur = next
# 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
dummy_node = ListNode(-1)
dummy_node.next = head
pre = dummy_node
# 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点pre
for _ in range(0,left - 1):
pre = pre.next
# 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
right_node = pre
for _ in range(right - left + 1):
right_node = right_node.next
# 第 3 步:切断出一个子链表(截取链表)
left_node = pre.next
succ = right_node.next
# 注意:切断链接
pre.next = None
right_node.next = None
# 第 4 步:同第 206 题,反转链表的子区间
reverse_linked_list(left_node)
# 第 5 步:接回到原来的链表中
pre.next = right_node
left_node.next = succ
return dummy_node.next