一、递归
思路:
利用之前做过的题目,获取链表中点(876题),将链表分为两段,参考合并有序链表(21题),将前半段和后半段进行排序后合并,但与之前不同的是,这里并不一定是有序的,就通过递归方式来处理,最后向上返回的一定是两个有序链表之间的合并。
注意:
获取链表中点相比于原题增加了个pre,pre 的作用是记录 slow 指针的前一个节点。当循环结束时,slow 指针指向链表的中间节点,而 pre 指针指向中间节点的前一个节点。
通过设置 pre.next = None,可以将链表从中间节点处分割成两个独立的链表。如果不使用 pre,就无法直接操作中间节点的前一个节点,也就无法完成链表的分割,只能返回中间节点是什么,而无法对前半段链表和后半段链表分开处理
代码:
python
class Solution:
# 876. 链表的中间结点
def midNode(self, head):
slow = fast = head
while fast and fast.next:
pre = slow
slow = slow.next
fast = fast.next.next
pre.next = None
return slow
# 21. 合并两个有序链表
def merge(self, list1, list2):
cur = dum = ListNode()
while list1 and list2:
if list1.val < list2.val:
cur.next = list1
list1 = list1.next
else:
cur.next = list2
list2 = list2.next
cur = cur.next
cur.next = list1 if list1 else list2
return dum.next
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 如果链表为空或者只有一个节点,无需排序
if head is None or head.next is None:
return head
# 找到中间节点 head2,并断开 head2 与其前一个节点的连接
# 比如 head=[4,2,1,3],那么 midNode 调用结束后 head=[4,2] head2=[1,3]
head2 = self.midNode(head)
head = self.sortList(head)
head2 = self.sortList(head2)
return self.merge(head, head2)
复杂度分析:
- 时间复杂度:O(nlogn),其中 n 是链表长度。递归式 T(n)=2T(n/2)+O(n),由主定理可得时间复杂度为 O(nlogn)。从图形上理解,递归深度是 O(logn),每一层的链表长度之和是 O(n)。计算高为 O(logn),底边长为 O(n) 的矩形面积,得到 O(nlogn)。
- 空间复杂度:O(logn)。递归需要 O(logn) 的栈开销。
参考:
二、归并排序
思路:
暂时看不懂。。后面再来填坑吧我累了...