一、两两交换链表中的节点
leetcode 24 两两交换链表中的节点
思路:使用cur_ptr
和next_ptr
进行链表的节点交换,注意节点交换的顺序和while循环跳出的条件,注意next_ptr
是None
的情况。
note:并且还需要采用虚拟头结点来避免在交换头结点和第二个节点的时候出现的头结点错乱的情况
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummyHead = ListNode(next = head)
pre_ptr = dummyHead
cur_ptr = head
while cur_ptr and cur_ptr.next:
node2 = cur_ptr.next
node3 = node2.next
pre_ptr.next = node2
node2.next = cur_ptr
cur_ptr.next = node3
pre_ptr = cur_ptr
cur_ptr = node3
return dummyHead.next
二、删除链表的倒数第N个节点
leetcode 19 删除链表的倒数第N个节点
思路:两个指针fast
和slow
,先让fast
往前走N个节点,然后fast
和slow
同时向后遍历,直至fast指针到链表尾。
注意点:注意最后slow.next
才是那个想删除的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummyHead = ListNode(next = head)
quick, slow = dummyHead, dummyHead
for i in range(n):
quick = quick.next
while quick.next != None:
quick = quick.next
slow = slow.next
slow.next = slow.next.next
return dummyHead.next
三、链表相交
- 先遍历,得到两个链表的长度
len_a
,len_b
- 把比较长的那个链表先往后遍历
abs(len_a - len_b)
个节点 - 一起遍历,直至两个指针相等,如果到最后没有相等的节点,返回
None
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
dummyHeadA = ListNode(next = headA)
dummyHeadB = ListNode(next = headB)
cur_node_a = headA
cur_node_b = headB
len_a, len_b = 0, 0
while cur_node_a:
len_a += 1
cur_node_a = cur_node_a.next
while cur_node_b:
len_b += 1
cur_node_b = cur_node_b.next
start_a, start_b = headA, headB
if len_a > len_b:
for i in range(len_a - len_b):
start_a = start_a.next
else:
for i in range(len_b - len_a):
start_b = start_b.next
while start_a:
if start_a == start_b:
return start_b
else:
start_a = start_a.next
start_b = start_b.next
return None
四、环形链表Ⅱ
leetcode 142 环形链表Ⅱ
首先需要判断链表内是否有环
- 初始化
fast
,slow
两个指针,fast
指针每次走两步,slow
指针每次走一步 - 如果
fast==slow
,那么说明链表存在环 - 如果
fast==None
,那么说明无环
在确定链表有环的情况下,如何判断哪里是链表的环的入口呢?
- 假设链表分为三个部分:无环区域长度为
out_loop
,环内长度为loop
,两个指针相遇时离入环区域距离len_enter
。 out_loop + k_fast * loop + len_enter = 2 * (out_loop + len_enter + k_slow * loop)
这里的k_fast和k_slow代表快指针和慢指针分别走过多少圈环- 化简后发现,
(k_fast - k_slow) * loop = out_loop + len_enter + k_slow * loop
- 也就是说,slow指针走过的步数一定是loop的整数倍
- 再进行化简,
out_loop = (k_fast - 2 * k_slow - 1) * loop +(loop - len_enter)
- 这也就意味着,在现在的基础上再走
out_loop
步的话,就相当于fast指针在现在位置的基础上再走(k_fast - 2 * k_slow - 1)
圈 +(loop - len_enter)
步,此时fast也会回到环的入口
此时就可以完美地得到环的入口在哪里了,简单地来说,就是确定链表存在环路后,使得find_enter = head
,然后使得find_enter = find_enter.next
,fast = fast.next
,直到fast == find_enter
即可(注意保存入口的index)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 判断链表有没有环
fast, slow = head, head
while fast != None and fast.next != None:
fast = fast.next.next
slow = slow.next
if fast == slow:
find_enter = head
while find_enter != fast:
find_enter = find_enter.next
fast = fast.next
return fast
return None
总结
最后一题需要一些数学推导,但是对链表的使用和认识非常重要。如果没有看懂可以去看代码随想录的解析