反转链表
一.反转整个单链表
链表的结构:1->2->3->4->5->NULL
class ListNode: def __init__(self, x): self.val = x self.next = None
1.迭代方法
-
分析:
假设链表的结构是:1–>2–>3–>N
反转后的结果就是N<–1<–2<–3
也就是
将所有的箭头换向,然后在最前面加个None,最后的None去掉
假设每个节点有三个方向,pre,cur,nxt分别对应前面被指向的节点,当前节点,指向的节点(如:节点2的pre就是1节点,cur就是当前的2节点,nxt就是3节点),由于1节点没有pre,假设为None
那么进行迭代的过程就是:
- 将1节点指向的2节点打断,指向pre节点(假设的N节点),然后将pre,cur,nxt向后移动一格,再进行下一次迭代,此时的结果就是:
N<--1 2-->3-->N
, pre为1节点,cur为2节点,nxt为3节点 - 将cur(2节点)指向nxt(3节点)的箭头打断,重新指向pre(1节点),然后将pre,cur,nxt向后移动一格,再进行下一次迭代,此时的结果就是:
N<--1<--2 3-->N
, pre为2节点,cur为3节点,nxt为None - 将cur(3节点)指向nxt(None)的箭头打断,重新指向pre(2节点),然后将pre,cur,nxt向后移动一格,再进行下一次迭代,此时的结果就是:
N<--1<--2<--3 N
, pre为3节点,cur为None,nxt没有,当cur为None时,停止迭代
- 由上可以看到,最后反转后的链表头部head就是3节点对应的pre,返回pre
-
代码
- 伪代码
class Solution: def reverseList(self, head: ListNode) -> ListNode: pre = None cur = head nxt = cur.next while cur != None: cur.next = pre pre = cur cur = nxt nxt = cur.next return pre
考虑到cur可能没有next,优化代码后
- 代码
class Solution: def reverseList(self, head: ListNode) -> ListNode: pre = None cur = head while cur: nxt = cur.next cur.next = pre pre = cur cur = nxt return pre
2.递归方法
二.反转链表前 N 个节点
将链表的前 n 个节点反转(n <= 链表长度)
输入: 1–>2–>3–>4–>N , 3
输出: 3–>2–>1–>4–>N
1.迭代方法
-
分析
按照反转整个链表的方式,区别就在于第1步和最后判断迭代结束的第三步存在区别:
- 在第1步中,将1节点指向2节点的指向打断,指向None应该变为指向第n+1节点
- 其他的不变,还是反转
- 到第3步中,
当cur为None时,停止迭代
变为当cur为第n+1节点时,停止迭代
-
代码
class Solution: def reverseList(self, head: ListNode,n) -> ListNode: # 记录第n+1节点为n_and_1 tmp = head for i in range(0,n): tmp = tmp.next n_and_1 = tmp # 迭代反转 pre = None cur = head while cur.val != n_and_1.val: nxt = cur.next if pre: # pre不为None时,调换箭头方向 cur.next = pre else: # pre为None时,说明是第一个节点,则需要指向n+1节点 cur.next = n_and_1 pre = cur cur = nxt return pre
2.递归方法
三、反转链表的一部分
给一个索引区间
[m,n]
(索引从 1 开始),仅仅反转区间中的链表元素。输入: 1–>2–>3–>4–>5–>N , 2, 4
输出: 1–>4–>3–>2–>5–>N
1.迭代方法
-
分析:
定义head为第m个节点,last为第n个节点
按照反转整个链表的方式分析,存在以下区别:
- 第m-1个节点指向第m个节点的箭头,应该改为第m-1个节点指向第n个节点.(如果m==1,则没有m-1,不需要操作,设置pre为None)
- 如果cur是开始的head(第m个节点),则不是将指向nxt的箭头指向pre,而是指向第n+1节点
# 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: ListNode, m: int, n: int) -> ListNode:
# 记录起始的pre(第m-1个节点)
# 记录起始的cur
if m == 1:
pre = None
cur = head
else:
tmp = head
for i in range(0, m - 2):
tmp = tmp.next
pre = tmp
cur = pre.next
# 记录第n节点为 n_node
# 记录第n+1节点为 n_and_1
tmp = head
for i in range(0, n - 1):
tmp = tmp.next
n_node = tmp
n_and_1 = n_node.next
# 迭代反转
for i in range(0, n - m + 1):
nxt = cur.next
if i == 0:
if m != 1:
pre.next = n_node
cur.next = n_and_1
else:
cur.next = pre
pre = cur
cur = nxt
return head if m != 1 else pre
if __name__ == '__main__':
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
head.next.next.next.next = ListNode(5)
so = Solution()
head = so.reverseList(head, 2, 4)
while head != None:
print(head.val)
head = head.next
-
迭代最优方法:
- 分析
- 在链表最前面加上一个p节点:p–>1–>2–>3–>4–>5–>N
p_node = ListNode(0) p_node.next = head
- 定义pre,cur指针,分别指向p节点和head节点(1节点)
pre, cur = p_node, head
- 移动pre,cur节点,使cur节点到达left节点,并且将此时的pre节点和cur节点记录下来,将指定的区域倒换后,这两个节点要分别指向right节点和right+1节点
for _ in range(1, left): pre = pre.next cur = cur.next first, second = pre, cur
此时:
p–>1–>2–>3–>4–>5–>N
pre–>1节点 ,cur–>2节点
- 将2-4节点中间区域的箭头掉头
for _ in range(left, right + 1): nxt = cur.next cur.next = pre pre = cur cur = nxt
此时:
p–>1<——>2<–3<–4 5–>N
pre指向4节点,cur指向5节点
- 将记录下来的节点分别指向right节点和right+1节点
first.next = pre second.next = cur
此时:p–>1–>4–>3–>2–>5–>N
- 最终代码
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseList(self, head: ListNode, left, right) -> ListNode:
p_node = ListNode(0)
p_node.next = head
pre, cur = p_node, head
for _ in range(1, left):
pre = pre.next
cur = cur.next
first, second = pre, cur
for _ in range(left, right + 1):
nxt = cur.next
cur.next = pre
pre = cur
cur = nxt
first.next = pre
second.next = cur
return p_node.next
if __name__ == '__main__':
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
head.next.next.next.next = ListNode(5)
so = Solution()
head = so.reverseList(head, 1, 4)
while head != None:
print(head.val)
head = head.next