Leetcode 148 给链表排序

Leetcode 148 给链表排序_第1张图片
就是你想的那个意思,给链表排序。
最简单的办法是,读取链表里的数字存到数组里,然后给数组排个序,最后放回去,时间复杂度O(nlogn)空间复杂度O(n)。这是很自然而然的想法。

但是他妈的字节跳动要求你的空间复杂度必须是O(1),也就是说你得原地排序。

那怎么办呢,首先原地排序,我想到了归并排序,正好leetcode21题要求写合并两个有序链表,可以用上。但是仔细一想发现不会,归并排序会压栈,这样的话一样会有空间开销,空间复杂度为O(logn),空间复杂度主要取决于递归调用的栈空间。

那么我们不能用传统的归并排序思路来做,我们需要自底向上进行归并排序。 这里看官方题解怎么说
Leetcode 148 给链表排序_第2张图片
来看代码

ListNode* sortList(ListNode* head) 
    {
        if(!head) return head;
        int length;
        ListNode* p=head;
        while(p!=nullptr)
        {
            length++;
            p=p->next;
        }
        ListNode* vh=new ListNode(0,head);
        //每次for循环都会将subLength扩大两倍
        for(int subLength=1;subLength<length;subLength*=2)
        {
            ListNode* prev=vh;
            ListNode* cur=vh->next;

			//每次按照subLength的长度分割出两条链表,然后让他俩归并排序一遍,然后再接回去,如此反复到结尾
            while(cur!=nullptr)
            {
                ListNode* head1=cur;
                for(int i=1;i<subLength;i++)
                {
                    if(cur->next==nullptr)
                        break;
                    cur=cur->next;
                }
                
                ListNode* head2=cur->next;
                cur->next=nullptr;
                cur=head2;
                for(int i=1;i<subLength;i++)
                {
                    if(cur==nullptr || cur->next==nullptr)
                        break;
                    cur=cur->next;
                }

                ListNode* next=nullptr;
                if(cur!=nullptr)
                {
                    next=cur->next;
                    cur->next=nullptr;
                }

                ListNode* merged=mergeTwoLists(head1, head2);
                prev->next=merged;
                
                while(prev->next!=nullptr)
                    prev=prev->next;

                cur=next;
            }
        }
        return vh->next;
    }
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        ListNode* vh=new ListNode;
        ListNode* p=vh;
        ListNode* p1=l1;
        ListNode* p2=l2;
        while(p1!=nullptr && p2!=nullptr)
        {
            if(p1->val<=p2->val)
            {
                p->next=p1;
                p1=p1->next;
            }
            else
            {
                p->next=p2;
                p2=p2->next;
            }
            p=p->next;
        }
        if(p1!=nullptr)
        {
            p->next=p1;
        }
        if(p2!=nullptr)
        {
            p->next=p2;
        }
        return vh->next;
    }

这种题目各个大厂面试都很喜欢考,为什么呢?首先,这题目有足够的优化空间,面试官可以通过你用的方法区分面试者的水平。 遇到变态的面试官可能会要求你一定要写出最优的算法。其次,链表排序这名字就很好记,面试的时候随手就能想到出这一题,然后看你吭哧吭哧写半天,对于他们来说,既不用废自己脑子,又可以折磨你,的确是一种精神上的享受。

而对于我们这种苦逼的面试者,只能尽力将遇到的这种题目的最优解法背下来,才有可能通过面试。
诸君,共勉吧,希望有朝一日,我们能脱离算法题的折磨

你可能感兴趣的:(算法题专栏,链表,leetcode,算法)