LeetCode Merge Two Sorted Lists and Sort List

来源:互联网 发布:不可逆矩阵qr分解 编辑:程序博客网 时间:2024/05/29 02:39

大家好,我是刘天昊,这次给大家带来的是链表的问题先说说 Merge Two Sorted 

没记错的话这是第二次写关于链表的博客,这次抛砖引玉是为了和大家谈谈合并排序

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

题目描述合并两个排序的链表因为比较简单,那么我就直接注释下代码吧

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {    if(l1==NULL)// l1为空返回l2
    {        return l2;    }    if(l2==NULL)//l2为空返回l1 
    {        return l1;    }    struct ListNode *res,*p;//定义一个是头指针res,一个是用来移动的指针    if(l1->val<l2->val)//如果l1值小先把l1的值放进头指针    {        res=l1;        l1=l1->next;    }    else//    {        res=l2;        l2=l2->next;    }    p=res;//让p指向头,方便移动    while(l1!=NULL&&l2!=NULL)//当l1或者l2不为空时 
    {        if(l1->val<l2->val)        {            p->next=l1;            l1=l1->next;        }        else        {            p->next=l2;            l2=l2->next;        }        p=p->next;    }    if(l1!=NULL)//l1不为空,把后面的连到l1上    {        p->next=l1;    }    else//l2不为空    {        p->next=l2;    }    return res;//返回头指针}
好,自己跑跑理解,我们再来基于这题的基础来来做下题

Sort List

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

链表的排序问题,链表排序也是经常面试考验的

来说说看有哪些方案

1.创建一个数组和链表等长O(n),拷贝内容到数组里O(n),随机快排序O(nlogN),拷贝到链表里O(n)

总时间O(nlogn)空间O(n)符合题意,但是太慢

2.直接快排序链表(没做,推荐读者试试,或者我以后po出来)

3.合并排序(其实我只是想说这个)链表排序最优的方案就是合并排序

leetcode的题目有很多优点要好好利用

我们先用上面的方案对两个链表进行合并

struct ListNode* merge(struct ListNode* l1, struct ListNode* l2) {    if(l1==NULL)    {        return l2;    }    if(l2==NULL)    {        return l1;    }    struct ListNode *res,*p;    if(l1->val<l2->val)    {        res=l1;        l1=l1->next;    }    else    {        res=l2;        l2=l2->next;    }    p=res;    while(l1!=NULL&&l2!=NULL)    {        if(l1->val<l2->val)        {            p->next=l1;            l1=l1->next;        }        else        {            p->next=l2;            l2=l2->next;        }        p=p->next;    }    if(l1!=NULL)    {        p->next=l1;    }    else    {        p->next=l2;    }    return res;}


一摸一样的代码就改了函数名,怎么样,很好理解吧接下来重点来了

struct ListNode* sortList(struct ListNode* head) {    if(head==NULL||head->next==NULL)    {        return head;    }    else    {        struct ListNode *fast=head;        struct ListNode *slow=head;        while(fast->next!=NULL&&fast->next->next!=NULL)        {            fast=fast->next->next;            slow=slow->next;        }        fast=slow;        slow=slow->next;        fast->next=NULL;        fast=sortList(head);        slow=sortList(slow);        return merge(fast,slow);    }}

运行Accepted好神奇,我来讲解下吧

首先我们其实应该先在下面这个代码开始

我们判断传进来的链表头指针不能就是一个或者空

然后我们用快慢指针找到链表的中部(这个可以理解吧,快的跑的是慢的两倍,快的到尾部,慢的在中间)

然后把链表从中间断开(让快指针到满指针那里,慢指针往后移一步,快指针的下一个为空,分为一个以传进来的头指针为头,一个为慢指针为头的两个链表)

然后递归(就是咋门不断的分,分到只有一个元素或者没有元素时候,返回,然后开始尾递归,不断的合并两个排好序(为什么是排号序的我下面解释)的链表)

最后得到了一个完整的排号序的链表

时间复杂度可以用主定理法直接得到O(nlogn)空间复杂度O(1)因为我们只申请了常数的内存。

现在说说为什么是排号序的

我们不断的分分到每个只有一个元素

然后开始尾递归的合并(两个只有一个元素的链表,执行了上面的代码得到了一个两个元素的排号序的链表(其实不一定有可能还是一个这里这样说方便理解))

接下来就是两个有两个元素的排号学的链表合并成一个四个元素的链表,(当然也有可能是2+1,2+0,1+1,1+2等可以自己在机子上调试)

最后得到一个整的排号序的链表

原创粉丝点击