返回
巧分链表:让小于 x 的元素优先排队
前端
2023-11-03 02:41:15
前言
在计算机科学的海洋中,链表可谓是一艘不可或缺的航船。今天,我们踏上算法之旅,探索一个看似简单却蕴含妙趣的课题:如何将链表中小于特定值 x 的元素与大于或等于 x 的元素分割开来。leetcode 86 题正是这样一个分而治之的典型案例。
任务解读
给你一个链表的头节点 head 和一个特定值 x,你的使命是将链表一分为二:
- 第一部分包含所有小于 x 的节点,按原有顺序排列。
- 第二部分包含所有大于或等于 x 的节点,同样按原有顺序排列。
两个部分之间可以采用任何连接方式。
算法精髓:分而治之
分而治之是一种强大的算法范式,它通过递归地将大问题分解成更小的子问题来解决。对于链表分割问题,我们可以将链表递归地分成两部分:
- 基线情况: 如果链表为空或只有一个节点,则不需要分割。
- 递归步骤: 否则,比较头节点的值与 x:
- 如果头节点值小于 x,则将其保留在第一部分,并递归处理剩余链表。
- 如果头节点值大于或等于 x,则将其移至第二部分,并递归处理剩余链表。
- 合并步骤: 将第一部分的尾节点与第二部分的头节点连接起来。
代码实现
def partition(head: ListNode, x: int) -> ListNode:
"""
将链表分割为两部分,小于 x 的元素在前,大于或等于 x 的元素在后。
参数:
head:链表的头节点
x:分割值
返回:
分割后的链表头节点
"""
# 定义两个虚拟头节点,用于连接两个部分
pre_head1 = ListNode(0)
pre_head2 = ListNode(0)
ptr1 = pre_head1
ptr2 = pre_head2
# 遍历原链表
while head:
# 如果当前节点的值小于 x
if head.val < x:
# 将其添加到第一部分
ptr1.next = head
ptr1 = ptr1.next
# 否则
else:
# 将其添加到第二部分
ptr2.next = head
ptr2 = ptr2.next
# 移动到下一个节点
head = head.next
# 连接两个部分
ptr1.next = pre_head2.next
ptr2.next = None
# 返回第一部分的头节点
return pre_head1.next
假设我们有一个链表:[1, 4, 3, 2, 5, 2],分割值为 x = 3。
- 比较头节点 1 与 3:1 < 3,将其保留在第一部分。
- 递归处理剩余链表 [4, 3, 2, 5, 2]。
- 比较头节点 4 与 3:4 > 3,将其移至第二部分。
- 递归处理剩余链表 [3, 2, 5, 2]。
- 比较头节点 3 与 3:3 = 3,将其保留在第一部分。
- 递归处理剩余链表 [2, 5, 2]。
- 继续此过程,直到所有节点都被处理完毕。
- 最终,我们将第一部分和第二部分连接起来:
第一部分:[1, 3]
第二部分:[4, 2, 5, 2]
通过巧妙地运用分而治之思想,我们轻而易举地解决了链表分割问题。这个算法不仅高效实用,而且为我们提供了一种解决复杂问题的思路。下次遇到链表难题时,不妨试试分而治之,也许能带给你意想不到的惊喜!