leetcode 148. 排序链表 (归并排序的迭代写法)

题目描述
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]

归并排序的简要步骤:将数组划分为只有一个元素的子数组,然后依次向上合并,直到合并到数组长度等于原始数组长度。类似于下图:
在这里插入图片描述
对于链表而言求解时也是按照这种思路,只不过多了一些链表的属性。首先统计链表的长度,由于最后链表的头结点会发生变化,因此设置一个虚拟头结点。

  • 将数组划分,划分长度为1,2,4……
  • 合并每一层的链表,合并时两两合并,需要找到合并时的第一个链表的头结点以及第二个链表的头结点,然后按照归并的思路合并,合并结束后会出现一些未被合并的部分,需要再一次合并。合并结束后该层的下一个需要合并的两个链表再依次进行上述的操作。cur的next指针需要指向second,即将这层的链表连起来,此时second是本层这一次合并的第一个链表的头结点。
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        int n=0;
        for(auto p=head;p;p=p->next) n++;//统计链表节点个数
        auto dummpy=new ListNode(-1);//虚拟头结点
        dummpy->next=head;
        for(int i=1;i<n;i*=2)//分层
        {
            auto cur=dummpy;
            for(int j=0;j+i<n;j+=2*i)//对每层操作,每层需要合并的链表为2*i个,需要合并 i 组
            {
                auto first=cur->next,second=first;//该层需要合并的两个链表
                for(int k=0;k<i;k++) second=second->next;
                int f=0,s=0;
                while(f<i && s<i && second) 
                {
                    if(first->val <= second->val) cur=cur->next=first,first=first->next,f++;
                    else cur=cur->next=second,second=second->next,s++;
                }
                //有可能有部分没合并
                while(f<i) cur=cur->next=first,first=first->next,f++;//第一部分长度肯定是i
                while(s<i&&second) cur=cur->next=second,second=second->next,s++;//第二部分长度有可能小于i
                cur->next=second;//将排好序的链表尾 链接 到 j+2i 下一2i链表 的表头,循环完毕后 second 为下一2i链表表头
            }
        }
        return dummpy->next;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值