题目描述
在 O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序
示例1:
输入: 4->2->1->3
输出: 1->2->3->4
示例2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
思路
1.题目要求时间复杂度为O(nlogn)和O(1)的空间复杂度,因此只能从链表的方向去解决
2.在这种情况下,我们可以用快慢指针将链表一分为二,用递归的方式将链表分解到一个个结点并用链表合并的方式将结点组合起来,这样就生成了一个有序的链表
链表结点结构
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
代码
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
pre, slow, fast = None, head, head
while fast and fast.next:
pre, slow, fast = slow, slow.next, fast.next.next
pre.next = None
return self.merge(*map(self.sortList, (head, slow)))
def merge(self, h1, h2):
dummy = tail = ListNode(None)
while h1 and h2:
if h1.val <= h2.val:
tail.next, h1 = h1, h1.next
else:
tail.next, h2 = h2, h2.next
tail = tail.next
tail.next = h1 or h2
return dummy.next
代码解释
1.merge
函数的作用是将两个链表合并
2.sortList
函数里每次将链表一分为二找到中间结点slow
3.将head
和slow
分别作为参数传入sortList
进行递归,递归到最底层时返回两个结点
4.将这里两个结点用*
作为merge
函数的参数
5.这样从递归最底层开始return
,最终生成一条有序的链表
复杂度分析
时间复杂度
1.假设用T(n)描述对n个结点的访问
2.找到slow
的时间复杂度是O(n),map
花费了2 * T(n/2)
3.假设最后合并的两条链表长度都是n/2,则merge
的时间复杂度是O(n)
总共T(n) = 2 * T(n/2) + O(n),所以T(n) = O(nlogn)
空间复杂度
dummy
,tail
和其他变量用了O(1)的空间,但是递归的时候用了O(logn)的空间,所以这个解法还是有点瑕疵