ps:中括号[] 中的数字,表示此算法题在 力扣 中的序号,直接搜索序号即可找到原题。
[21]合并两个链表
class Solution(object):
def mergeTwoLists(self, list1, list2):
"""
:type list1: Optional[ListNode]
:type list2: Optional[ListNode]
:rtype: Optional[ListNode]
"""
dummy = ListNode(-1)
p = dummy
p1 = list1
p2 = list2
while p1 and p2:
if p1.val > p2.val:
p.next = p2
p2 = p2.next
else:
p.next = p1
p1 = p1.next
# p指针不断向后移动
p = p.next
# 如果某一个链表结束了。直接将剩余的移动到新链表上
if p1:
p.next = p1
if p2:
p.next = p2
return dummy.next
[86]分割链表
class Solution(object):
def partition(self, head, x):
"""
:type head: ListNode
:type x: int
:rtype: ListNode
"""
dummy1 = ListNode(-1)
dummy2 = ListNode(-1)
p1 = dummy1
p2 = dummy2
p = head
while p:
if p.val >= x:
p2.next = p
p2 = p2.next
else:
p1.next = p
p1 = p1.next
# 切开原链表的每个 next 连接,如果不断开源链表的链接关系,可能会出现环形结构。
temp = p.next
p.next = None
p = temp
# 重新连接链表
p1.next = dummy2.next
return dummy1.next
[23]合并 K 个升序链表
import heapq
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
# 难点在于如何在k个元素中快速找到最小的值
# 这里借助堆这种数据结构,本体采用二叉堆: import heapq
if not lists:
return None
dummy = ListNode(-1)
# heaqp 最小堆
pq = []
for head in lists:
if head:
heapq.heappush(pq, (head.val, head)
while pq:
# 获取最小的节点
node = heapq.heappop(qp)[1]
p.next = node
if node.next:
heapq.heappush(pq, (node.next.val, node.next))
p = p.next
return dummy.next
[19]删除链表的倒数第 N 个结点
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
dummy = ListNode(-1)
dummy.next = head
# 删除倒数第 n 个,要先找倒数第 n + 1 个节点
x = self._findFromEnd(dummy, n + 1)
x.next = x.next.next
return dummy.next
# 返回链表的倒数第 k 个节点
def _findFromEnd(self, head, k):
p1 = head
# p1 先走 k 步
for i in range(k):
p1 = p1.next
p2 = head
# p1 和 p2 同时走 n - k 步
while p1 != None:
p2 = p2.next
p1 = p1.next
# p2 现在指向第 n - k + 1 个节点,即倒数第 k 个节点
return p2
[141]判断链表中是否有环
每当慢指针 slow
前进一步,快指针 fast
就前进两步。
如果 fast
最终遇到空指针,说明链表中没有环;如果 fast
最终和 slow
相遇,那肯定是 fast
超过了 slow
一圈,说明链表中含有环。
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast= fast.next
if slow == fast:
return True
return False
[ ]寻找环起点
def detectCycle(head: ListNode) -> ListNode:
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
break
# 判断是否存在环
if not fast or not fast.next:
return None
slow = head
# 让慢指针指向 head, 再次相遇就是环的起点
while slow != fast:
fast = fast.next
slow = slow.next
return slow
这里讲一下其中的原理:
我们假设快慢指针相遇时,慢指针 slow
走了 k
步,那么快指针 fast
一定走了 2k
步:
fast
一定比 slow
多走了 k
步,这多走的 k
步其实就是 fast
指针在环里转圈圈,所以 k
的值就是环长度的「整数倍」。
假设相遇点距环的起点的距离为 m
,那么结合上图的 slow
指针,环的起点距头结点 head
的距离为 k - m
,也就是说如果从 head
前进 k - m
步就能到达环起点。
巧的是,如果从相遇点继续前进 k - m
步,也恰好到达环起点。因为结合上图的 fast
指针,从相遇点开始走k步可以转回到相遇点,那走 k - m
步肯定就走到环起点了:
[160]两个链表是否相交
-
解法一:将末尾的 node 节点 连接其中一个 head 节点,次问题就转换成了寻找环起点的问题了。
-
解法二:先便利 A,在遍历 B ,这样在相交节点,我们就就会进入公共部分,如图所示:
# 解法二
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
# p1 指向 A 链表头结点,p2 指向 B 链表头结点
p1, p2 = headA, headB
while p1 != p2:
# p1 走一步,如果走到 A 链表末尾,转到 B 链表
if p1 == None:
p1 = headB
else:
p1 = p1.next
# p2 走一步,如果走到 B 链表末尾,转到 A 链表
if p2 == None:
p2 = headA
else:
p2 = p2.next
# 如果相交,返回交点,如果不相交,返回空
return p1