本文介绍 LeetCode 题集中,有关链表的问题。
141. Linked List Cycle(环形链表)
问题描述
思路与代码
本题通过快慢指针追及问题的思路来解决。
代码如下:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
return True
return False
运行效果:
上述代码为二倍速的追及,实际上快指针的速度可以为慢指针的任何倍数。
三倍速的代码:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
fast, slow = head, head
while fast and fast.next and fast.next.next:
fast = fast.next.next.next
slow = slow.next
if fast == slow:
return True
return False
四倍速的代码:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
fast, slow = head, head
while fast and fast.next and fast.next.next and fast.next.next.next:
fast = fast.next.next.next.next
slow = slow.next
if fast == slow:
return True
return False
运行效果并无明显差异。
142. Linked List Cycle II(环形链表 II)
问题描述
思路与代码
参考官方题解,本题有哈希表和快慢指针两种方法。
LeetCode 142 官方题解
哈希表的方法相对容易理解:
代码如下:
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
set_visit = set()
set_visit.add(head)
while head:
if not head.next:
return None
if head.next in set_visit:
return head.next
else:
set_visit.add(head.next)
head = head.next
运行效果:
快慢指针法相对复杂:
快指针的速度为慢指针的 2 倍,当快慢指针相遇时,新定义一个指针指向起点,新指针与慢指针同时向前移动,速度相同,最终两者在入环点相遇。数学推导如下:
设快慢指针相遇时,慢指针在环中转了
k
1
k_1
k1? 圈,快指针转了
k
2
k_2
k2? 圈,故有:
(
a
+
k
1
?
b
+
c
)
?
2
=
a
+
k
2
?
b
+
c
?
a
=
(
k
2
?
2
?
k
1
)
?
b
?
c
(a + k_1 \cdot b + c) \cdot 2 = a + k_2 \cdot b + c \\ \ \\ a = (k_2 - 2 \cdot k_1) \cdot b - c
(a+k1??b+c)?2=a+k2??b+c?a=(k2??2?k1?)?b?c
代码如下:
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast, slow = head, head
while fast and slow:
if fast.next:
fast = fast.next.next
else:
return None
slow = slow.next
if fast == slow:
tmp = head
while tmp != slow:
tmp = tmp.next
slow = slow.next
return tmp
return None
运行效果:
206. Reverse Linked List(反转链表)
问题描述
思路与代码
本题有迭代法和递归法两种方法。
迭代法的思路比较简单,定义一个 pre 节点表示前一个节点,循环迭代即可。
代码如下:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
pre = None
while head:
tmp = head.next
head.next = pre
pre = head
head = tmp
return pre
运行效果:
递归法理解起来有点麻烦,可以参考下面题解中的动图:
题解-递归动图
代码如下:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
def rec(node: ListNode):
if not node or not node.next:
return node
node_new = rec(node=node.next)
node.next.next = node
node.next = None
return node_new
return rec(node=head)
运行效果:
92. Reverse Linked List II(反转链表 II)
问题描述
思路与代码
本题是前一题的变体,可以调用前一题的反转函数,完成片段内的反转,对于片段外的头尾部分拼接到反转后的片段前后即可。
代码如下:
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
def reverse_linked_list(head: ListNode):
pre = None
cur = head
while cur:
next = cur.next
cur.next = pre
pre = cur
cur = next
dummy = ListNode(-1)
dummy.next = head
pre = dummy
for _ in range(left - 1):
pre = pre.next
right_node = pre
for _ in range(right - left + 1):
right_node = right_node.next
left_node = pre.next
curr = right_node.next
pre.next = None
right_node.next = None
reverse_linked_list(left_node)
pre.next = right_node
left_node.next = curr
return dummy.next
运行效果:
24. Swap Nodes in Pairs(两两交换链表中的节点)
问题描述
思路与代码
本题的思路与前两题相似,定义两个指针(节点),依次对每对节点进行反转,然后将指针向前移动两位,循环迭代即可。
代码如下:
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy = ListNode(val=-1)
dummy.next = head
pre = dummy
while pre.next and pre.next.next:
first, second = pre.next, pre.next.next
first.next = second.next
second.next = first
pre.next = second
pre = first
return dummy.next
运行效果:
|