LeetCode No.148 Sort List

题目:

即对给定的链表进行排序,时间复杂度为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

结果:

猜你喜欢

转载自blog.csdn.net/qq_39178023/article/details/80161356