[C++]LeetCode: 125 Sort List (归并排序链表)

题目:Sort a linked list in O(n log n) time using constant space complexity.

思路:题目要求我们使用常数空间复杂度,时间复杂度为O(nlog(n)). 满足这个时间复杂度的有快速排序,归并排序,堆排序。插入排序时间复杂度为O(n^2). 双向链表用快排比较合适,堆排序也可用于链表,单项链表适合于归并排序。我们就用归并排序的思想来完成链表的排序。

首先是用快慢双指针找到链表中间的位置,然后分成前后端分别递归的归并排序,最后合并。

Attention:

1. 快慢指针找中间节点的方法,是常用方法,要熟练使用。

//将链表分成前后两部分 双指针找到中间节点
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast->next != NULL && fast->next->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
2. 链表的数据结构是如何实现归并的方法的。定义一个合并后的链表,然后把合适的节点放进去。思想和数组是一样的,只是链表操作不一样。

复杂度:如果这里我们考虑递归的栈空间的话,空间复杂度是O(lg(n))

AC Code:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if(head == NULL || head->next == NULL) return head;
        //将链表分成前后两部分 双指针找到中间节点
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast->next != NULL && fast->next->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* head2 = slow->next;
        slow->next = NULL;
        ListNode* head1 = head;
        head1 = sortList(head1);   //前半段归并排序
        head2 = sortList(head2);   //后半段归并排序
        return merge(head1, head2);
    }

private:
    ListNode* merge(ListNode* h1, ListNode* h2)
    {
        ListNode* dummyhead = new ListNode(0);
        ListNode* mlist = dummyhead;
        
        while(h1 != NULL && h2 != NULL)
        {
            if(h1->val <= h2->val)
            {
                mlist->next = h1;
                h1 = h1->next;
            }
            else
            {
                mlist->next = h2;
                h2 = h2->next;
            }
            mlist = mlist->next;
        }
        if(h1 != NULL)
        {
            mlist->next = h1;
        }
        if(h2 != NULL)
        {
            mlist->next = h2;
        }
        return dummyhead->next;
    }
};

我们也可以不使用递归的方法,自底向上的非递归版本的归并排序,空间复杂度就是常数了。可以看下这篇博文:sort list.
排序是面试中很常见和基础的一个主题,我们需要对各种常见的排序算法要熟悉。尤其是算法的原理,很多题目虽然没有直接考察排序的实现,但是会用到其中的思想,比如经典的topK问题,用到了快排的原理。这篇文章中有提到,可以看看:Median of Two Sorted Arrays.所以我们应该要更加注重排序算法的原理。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。