leetcode 92. 反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
翻转链表:
(迭代版本)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
curr = head
while curr:
nex = curr.next
curr.next = pre
pre = curr
curr = nex
return pre
(递归版本)
base case:如果链表只有一个节点的时候反转也是它自己,直接返回即可。
当链表递归反转之后,新的头节点是last,而之前的head变成了最后一个节点,别忘了链表的末尾要指向 None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head:
return None
if not head.next:
return head
last = self.reverseList(head.next)
head.next.next = head
head.next = None
return last
反转链表前 N 个节点
base case 变为n == 1,反转一个元素,就是它本身,同时要记录后驱节点。
刚才我们直接把head.next设置为 None,因为整个链表反转后原来的head变成了整个链表的最后一个节点。但现在head节点在递归反转之后不一定是最后一个节点了,所以要记录后驱successor(第 n + 1 个节点),反转之后将head连接上。
class Solution:
successor = None
def reverseN(self, head: ListNode, n: int) -> ListNode:
if not head:
return None
if n == 1:
successor = head.next
return head
last = self.reverseN(head.next, n - 1)
head.next.next = head
head.next = successor
return last
方案一:
先找到要翻转的 a 和 b 点,注意保存 a 的前驱节点 prea 和 b 的后继节点 bnex ,然后翻转从 a 到 b 的部分,之后修改指针指向,让prea.next = b, a.next = bnex
缺点是进行了多次扫描,代码如下:
翻转从m到n的完整代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if m == n:
return head
dummpy = ListNode(None)
dummpy.next = head
prea, b = dummpy, dummpy
for _ in range(m - 1):
prea = prea.next
for _ in range(n):
b = b.next
a = prea.next
bnex = b.next
pre = prea
curr = prea.next
while curr != bnex:
nex = curr.next
curr.next = pre
pre = curr
curr = nex
prea.next = b
a.next = bnex
return dummpy.next
方案二:
一次遍历,在遍历的时候同时进行翻转
看代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if m == n:
return head
dummpy = ListNode(None)
dummpy.next = head
pre = dummpy
for i in range(m - 1):
pre = pre.next
# pre 代表第m节点的前一个节点
curr = pre.next # curr代表第m个节点
temp_pre = ListNode(None) # 临时节点便于翻转链表
for i in range(m, n + 1): # 翻转从m到n的节点,注意是n+1,翻转完,temp_pre指向第n个节点,curr指向第n+1个节点
nex = curr.next
curr.next = temp_pre
temp_pre = curr
curr = nex
pre.next.next = curr # 第m个节点的下一个指向第n+1个节点
pre.next = temp_pre # 第m-1个节点的下一个指向第n个节点
return dummpy.next