24. 两两交换链表中的节点 - 力扣(LeetCode)
一次AC,重点是要画图梳理清楚交换节点的过程
# 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]:
dummy_node = ListNode(next=head)
cur = dummy_node
while cur.next != None and cur.next.next != None:
# 进行交换
temp = cur.next
cur.next = cur.next.next
temp.next = cur.next.next
cur.next.next = temp
# 更新cur
cur = cur.next.next
return dummy_node.next
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
一开始理解成顺序数第一个了,写完后发现是倒数第N个,于是在前面加了下对长度的统计
# 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]:
dummy_node = ListNode(next=head)
cur = dummy_node
length = 0
while cur.next:
length += 1
cur = cur.next
cur = dummy_node
for _ in range(length-n):
if cur.next:
cur = cur.next
else:
break
if cur.next:
cur.next = cur.next.next
return dummy_node.next
阅读代码随想录后发现,这题用快慢指针可以一次遍历就解决,大体思路为让slow和fast始终保持n个间距,则fast为None时则slow为倒数第n个
# 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: ListNode, n: int) -> ListNode:
# 创建一个虚拟节点,并将其下一个指针设置为链表的头部
dummy_head = ListNode(0, head)
# 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
slow = fast = dummy_head
# 快指针比慢指针快 n+1 步
for i in range(n+1):
fast = fast.next
# 移动两个指针,直到快速指针到达链表的末尾
while fast:
slow = slow.next
fast = fast.next
# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
slow.next = slow.next.next
return dummy_head.next
面试题 02.07. 链表相交 - 力扣(LeetCode)
一开始想要一次扫描就搞定,但是没想出来。快速扫了下解答,发现先计算了长度,结合上题很自然想到用快慢指针,一次AC
# 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:
lengthA = self.get_length(headA)
lengthB = self.get_length(headB)
delta = abs(lengthA-lengthB)
if lengthA > lengthB:
return self.get_joint_node(headA, headB, delta)
else:
return self.get_joint_node(headB, headA, delta)
def get_length(self, head):
dummy_head = ListNode(next=head)
cur = dummy_head
length = 0
while cur.next:
length += 1
cur = cur.next
return length
def get_joint_node(self, head_long, head_short, delta):
cur_short = ListNode(next=head_short)
cur_long = ListNode(next=head_long)
while delta > 0:
cur_long = cur_long.next
delta -= 1
while cur_short.next and cur_long.next:
if cur_short.next == cur_long.next:
return cur_long.next
else:
cur_short = cur_short.next
cur_long = cur_long.next
return None
142. 环形链表 II - 力扣(LeetCode)
这题之前做过,貌似有数学推到,根据快慢指针计算,但是自己现在想不起来了。
这题很直观的想法就是保留遍历过的Node,如果碰到重复的Node就说明有环,一次AC,代码如下:
# 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]:
history_node = []
cur = head
while cur:
if cur in history_node:
return cur
else:
history_node.append(cur)
cur = cur.next
return None
上面提到的推导在代码随想录,后面可以复习一下,下面是代码
# 快慢指针法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# If there is a cycle, the slow and fast pointers will eventually meet
if slow == fast:
# Move one of the pointers back to the start of the list
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
# If there is no cycle, return None
return None
总结
- 快慢指针有很多变体
- 检测链表是否有闭环可以通过快慢指针转换为追击相遇问题
附录
代码随想录算法训练营第四天 | 24. 两两交换链表中的节点 、19. 删除链表的倒数第N个节点、面试题-链表相交、142.环形链表II_小蛙先森的博客-CSDN博客