LeetCode 148. Sort List - 链表(Linked List)系列题19

这篇博客讨论了如何对链表进行排序,重点在于实现一个时间复杂度为O(n*logn)的解决方案。作者选择了归并排序算法,通过快慢指针找到链表中间节点,然后递归地将链表分成两半并分别排序,最后合并成一个有序链表。文章详细解释了算法的每一步,并给出了具体的Python代码实现。
摘要由CSDN通过智能技术生成

Given the head of a linked list, return the list after sorting it in ascending order.

Example 1:

Input: head = [4,2,1,3]
Output: [1,2,3,4]

Example 2:

Input: head = [-1,5,3,4,0]
Output: [-1,0,3,4,5]

Example 3:

Input: head = []
Output: []

Constraints:

  • The number of nodes in the list is in the range [0, 5 * 104].
  • -105 <= Node.val <= 105

Follow up: Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)?

这题还是要求对链表做排序,不像147. Insertion Sort List 指定要用插入排序。这题可以自己选择排序算法,但要求时间复杂度是O(n*logn),很显然插入排序的O(n^2)无法满足要求。试跑了一下147. Insertion Sort List 的代码果然超时。

由于指定要达到O(n*logn),在众多排序算法中首先想到的会是归并排序(merge sort),其核心思想就是把链表从中间分成两部分,如果两部分都是有序的那就可以重新合并使整个链表是有序的,前面已经刷过如何合并两个有序链表的题LeetCode 21. Merge Two Sorted Lists

如何使链表前后两部分变成有序的呢?可以分别把它们再各自分成两部分,一直递归调用下去,当最后两部分都只有一个节点时那就肯定是有序的了,然后依次合并返回,返回到了最上层合并之后整个链表就已经排好序了。

如何把链表从中间分成前后两部分呢?找到链表的中间节点,从中间节点断开就把链表分成了两个部分了。对于获取中间节点可以用快慢指针法。注意在使用快慢指针时,一开始快指针要指向第二节点,这样只剩两个节点时可以分成两部分各含一个节点,以免造成死循环。另外要注意的是分成两部分后前半部分的最后一个节点(中间节点)的next要指向空,以免递归调用时无法停止。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next:
            return head
        
        def getMid(h):
            if not h or not h.next:
                return h
            slow, fast = h, h.next
            while fast and fast.next:
                slow = slow.next
                fast = fast.next.next
                
            return slow
        
        mid = getMid(head)
        h1, h2 = head, mid.next
        mid.next = None
        h1 = self.sortList(h1)
        h2 = self.sortList(h2)
        
        preHead = ListNode(-1)
        cur = preHead
        while h1 and h2:
            if h1.val < h2.val:
                cur.next = h1
                h1 = h1.next
            else:
                cur.next = h2
                h2 = h2.next
            cur = cur.next
        
        cur.next = h1 if h1 else h2
        
        return preHead.next

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值