Leetcode Link: 148. 排序链表 - 力扣(LeetCode) (leetcode-cn.com)

题目

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

要求时间复杂度,额外空间复杂度

|700

解法一

思路:自上向下的递归。即我们在归并排序中的递归策略,从顶部开始,不断向下递归,直到递归到底停止,再一点一点返回来。如何找到中点是本思路的重中之重。

但是,这种方法虽然时间复杂度为,其空间复杂度收到递归栈的影响,其递归栈的深度就是该算法的空间复杂度,为

题解:

class Solution:
    # 找链表的中点,直接用快慢指针!
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        return self.mergeSort(head)
    
    def mergeSort(self, lists):
        if lists==None or lists.next==None:
            return lists
        else:
            # 找中点,中点为slow
            # 这里要思考,对于奇数偶数个节点,怎么找到他的中点,最后的那个None会有影响,最好画图想想。
            fast = lists
            slow = lists
            while(fast.next!=None):
                if fast.next.next!=None:
                    fast = fast.next.next
                    slow = slow.next
                else:
                    fast = fast.next
            # 获得右链表
            l_right = slow.next
            # 断开中点之后的节点,获得左链表
            # 一定记得要断开,要不然就是全部的链表了。
            slow.next = None
            l_left = lists
            
            leftList = self.mergeSort(l_left)
            rightList = self.mergeSort(l_right)
            mergeList = self.merge(leftList,rightList)
            return mergeList
        
    def merge(self, left, right):
        dummy = ListNode()
        cur = dummy
 
        while(left!=None and right!=None):
            if left.val < right.val:
                cur.next = left
                left = left.next
                cur = cur.next
            else:
                cur.next = right
                right = right.next
                cur = cur.next
        if left!=None:
            cur.next = left
        if right!=None:
            cur.next = right
        
        return dummy.next

解法二

思路:自下而上的排序。时间复杂度,空间复杂度

详细的题解可以参考:Sort List (归并排序链表)题解

题解:

class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 计算链表的长度
        cur = head
        N = 0
        while(cur):
            cur = cur.next
            N += 1
 
        # 自下向上开始排序并合并。
        dummy = ListNode(-1, head)
        cur = dummy.next
        last_end = dummy
        k = 1
        while(k < N):
            while(cur):
                ## 找左半部分的起点和终点
                left = cur
                for _ in range(0,k-1):
                    if cur.next:
                        cur = cur.next
                    else: 
                        # 如果左部分都不全,那不可能有右边,直接接上就行(因为左右都已经排好序了)
                        # 把“接上”的代码写在了下面,是等价的,因为一定没有右边。
                        break
                left_end = cur
                ## 找右半部分的起点
                ### 没有右半部分,说明也能直接接上左边。
                if not cur.next:
                    last_end.next = left
                    break
                else:
                    cur = cur.next
                    right = cur
                    for _ in range(0,k-1):
                        if cur.next:
                            cur = cur.next
                        else:
                            # 有右边就必须合并排序
                            break 
                    right_end = cur
 
                # cur 再走一步,为下一次循环做准备,然后就可以断开左右终点之后的节点了。
                cur = cur.next # 前面都是判断的 cur.next, 所以cur.next一定有,最次是None
                left_end.next = None
                right_end.next = None
                ## 合并左右,并接上上一次的尾巴
                last_end.next = self.mergeTwo(left, right)
                ### last_end移动到尾部(找到新的last_end)
                while(last_end.next):
                    last_end = last_end.next
            
            k *= 2
            # 重置,很重要。
            cur = dummy.next
            last_end = dummy          
        return dummy.next
 
    def mergeTwo(self, left, right):
        dummy = ListNode()
        cur = dummy
 
        while(left and right):
            if left.val < right.val:
                cur.next = left
                cur = cur.next
                left = left.next
            else:
                cur.next = right
                cur = cur.next
                right = right.next
        if left:
            cur.next = left
        if right:
            cur.next = right
        return dummy.next

启发和联系