【代码随想录】链表2
wbfwonderful Lv3

206.反转链表

题目链接 link

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

双指针(迭代)

只需要改变链表的next指针的指向,直接将链表反转,而不用重新定义一个新的链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head == None or head.next == None:
return head
pre = head
cur = head.next

head.next = None
while cur != None:
temp = cur.next
cur.next = pre
pre = cur
cur = temp

return pre

以上代码单独考虑了特殊情况,实际上可以写在一起,直接将 pre 设置为 None,cur 设置为 head 即可。

递归法

本质上是多次完成以下任务:将当前 cur.next 赋值为 pre,然后移动 cur 和 pre。可以使用递归的方法,写一个函数来多次完成上述过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
pre = None
cur = head
return self.reserve(pre, cur)

def reserve(self, pre, cur):
if cur == None:
return pre

temp = cur.next

cur.next = pre

pre = cur

cur = temp

return self.reserve(pre, cur)

24. 两两交换链表中的节点

题目链接 link

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
image

迭代法

设置一个虚拟头节点,然后进行两两交换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head == None or head.next == None:
return head

dummy_head = ListNode(0, head)
pre = dummy_head
cur1 = head
cur2 = head.next

while True:
lat = cur2.next
cur2.next = cur1
cur1.next = lat
pre.next = cur2

if lat != None and lat.next != None:
pre = cur1
cur1 = lat
cur2 = lat.next

else:
return dummy_head.next

19.删除链表的倒数第N个节点

题目链接 link

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

思路 1

直观方法,先遍历一遍,获取链表的长度,然后再遍历删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy_head = ListNode(0, head)
length = 0
cur = dummy_head.next

while cur != None:
length += 1
cur = cur.next

i = 0
cur = dummy_head.next
pre = dummy_head
while i < length - n:
cur = cur.next
pre = pre.next
i += 1

pre.next = cur.next

return dummy_head.next

思路 2

要求只遍历一遍链表:双指针的典型应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。(假设链表长度为 l,fast 移动了 l,slow 移动了 l - n,)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy_head = ListNode(0, head)
fast = dummy_head.next
slow = dummy_head.next
pre = dummy_head
i = 0
while fast != None:
if i < n:
i += 1
else:
slow = slow.next
pre = pre.next

fast = fast.next

pre.next = slow.next

return dummy_head.next

面试题 02.07. 链表相交

题目链接 link

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

示例:
image

输入两个 list,返回两个 list 相交的节点。

思路

如果两个 list 有相交的部分,那么一定在 list 的后半部分(尾部对齐)。那么可以使用快慢指针,首先遍历两个 list 的长度,找到其长度差 dif,让 fast 指针在长的 list 上先移动 dif,然后两个指针再一起移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
cur1 = headA
cur2 = headB
len1 = 0
len2 = 0
while cur1 != None:
len1 += 1
cur1 = cur1.next

while cur2 != None:
len2 += 1
cur2 = cur2.next

dif = abs(len2 -len1)

if len2 > len1:
fast = headB
slow = headA
else:
fast = headA
slow = headB

for i in range(dif):
fast = fast.next

while fast != None:
if fast == slow:
return fast

fast = fast.next
slow = slow.next

return None