题目:
即对给定的链表进行排序,时间复杂度为O(nlogn),空间复杂度为O(1)。
思路:
一开始我想的是用快速排序,然而在最坏情况下,快速排序时间复杂度退化到了O(n²),于是改用了discuss里面推荐的归并排序。顺便一提,因为数组的快排有两个指针,而现在的快排的对象是链表,像数组快排一样算出第一个元素所在的位置。
我在快排中找第一个元素位置的方法如图:
对左开右闭[head,list)链表排序,i遍历了除了第一个元素之外的所有元素。当i.val比key要小时,让loc指向loc.next,交换loc和i的值,这样做,保证了loc的值都比key要小。最后把loc和head的值(即key)交换。结果是loc的值为key值,loc前面的值比key小,右边比key大。
对于归并排序,因为题目要求O(1)的空间复杂度,所以采用了非递归的自底向上归并排序。自底向上归并的思路就是,先从间隔为1开始,把链表划分成一个一个区间,然后对相邻两个区间排序,循环这个操作。然后把间隔加倍,重复上述操作。说起来简单,代码还是有一定难度的。其中分隔节点的函数我是参考discuss的答案,比较巧妙,值得以后反复看。
代码:
class ListNode: def __init__(self, x): self.val = x self.next = None class Solution: def sortList(self, head): if head == None or head.next == None: return head result = ListNode(0) result.next = head length,i,current,temp = 0,1,head,result while head != None: length,head = length+1,head.next #算出head总长度 while i < length: current = result.next temp = result while current != None: left = current right = self.split(current,i) #从left开始数i个结点 current = self.split(right,i) #从right开始数i个结点,用于下个循环赋值给left temp = self.combine(temp,left,right) i *= 2 return result.next def split(self,head,gap): #在head链表中作分隔,前gap个结点为一部分,返回剩余部分的头节点 i = 1 while i < gap and head != None: head = head.next i += 1 if head == None: return None result = head.next head.next = None return result def combine(self,beforeHead,left,right): while left != None and right != None: if left.val < right.val: beforeHead.next = left left = left.next else: beforeHead.next = right right = right.next beforeHead = beforeHead.next if left != None: beforeHead.next = left else: beforeHead.next = right while beforeHead.next != None: beforeHead = beforeHead.next return beforeHead