返回

从小白入门到“上天”——《剑指 Offer II 029. 排序的循环链表》彻底解析

后端

导语

掌握循环链表的排序技巧

你好呀,各位小伙伴们!欢迎来到【刷题日记】之剑指 Offer II 029. 排序的循环链表。

俗话说得好,“万变不离其宗”,即使是循环链表,排序的本质也离不开那几个经典套路。因此,今天我们直接跳过那些抽象难懂的理论,一起直奔主题,从实战的角度来掌握循环链表的排序技巧!

排序的循环链表

题目

首先,我们来看一下这道题目的

给定一个循环链表的头节点 head,按升序将其排序并返回排好序的链表的头节点。请注意, 此题要求返回排好序的链表,而不是其副本。

思路解析

收到,我们先来分析一下这道题目的思路。

既然题目要求返回排好序的链表,那么我们就不能使用常规的排序算法,比如冒泡排序、快速排序等,因为这些算法会破坏链表的结构。所以,我们需要找到一种能够在不破坏链表结构的情况下对链表进行排序的方法。

于是,我们想到了归并排序 ,这个算法可以巧妙地避开链表结构破坏的陷阱,同时又保证了排序的准确性。具体步骤如下:

  1. 将链表拆分为两个相等的子链表。
  2. 对每个子链表进行递归排序。
  3. 将排好序的子链表合并成一个排好序的链表。

代码实现

有了思路,接下来我们就来写代码吧。

def sortList(head):
    # 如果链表为空或只有一个节点,直接返回
    if not head or not head.next:
        return head

    # 找到链表的中点
    slow, fast = head, head.next
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

    # 将链表拆分为两个子链表
    mid = slow.next
    slow.next = None

    # 对每个子链表进行递归排序
    left = sortList(head)
    right = sortList(mid)

    # 将排好序的子链表合并成一个排好序的链表
    return mergeTwoLists(left, right)

def mergeTwoLists(l1, l2):
    # 创建一个虚拟头节点
    dummy = ListNode(0)
    curr = dummy

    # 遍历两个链表,将较小的节点添加到新的链表中
    while l1 and l2:
        if l1.val < l2.val:
            curr.next = l1
            l1 = l1.next
        else:
            curr.next = l2
            l2 = l2.next
        curr = curr.next

    # 将剩余的节点添加到新的链表中
    if l1:
        curr.next = l1
    if l2:
        curr.next = l2

    # 返回新的链表
    return dummy.next

结语

本期【刷题日记】到此结束,希望对大家有所帮助。我们下期再见!