力扣-每日一题20201121-148.排序链表

力扣-每日一题20201121-148. 排序链表

解题思路:

时间复杂度为O(nlogn)的排序算法有归并排序堆排序快排**,快排的时间复杂度最坏达到O(n²)。

其中最适合链表的排序算法是归并排序,归并排序有两种实现方式:

  • 一种是自顶向下的递归实现,空间复杂度为***O(logn)***

  • 一种是自底向上的实现,空间复杂度为***O(1)***

自顶向下方法实现思想

  1. 使用快慢指针找到链表的中点,将链表拆分为两个部分。

  2. 对两个子链表进行递归排序。

  3. 将有序的两个子链表进行合并。

自底向上方法实现思想

  1. 使用min_length来表示每次需要合并的子链长度,初始值为1。
  2. 将链表以min_length为长度进行拆分,最后一个子链可以不足min_length。合并后的链表长度为2*min_length。
  3. 将min_length翻倍,重复第二部的操作,直至2*min_length的值大于等于length。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == nullptr) //判断链表是否为空
            return nullptr;
         
        int len = 0;
        ListNode* t = head;
        while(t!=nullptr){ // 计算链表的长度
            len++;
            t = t->next;
        }

        int min_length = 1;
        ListNode* t_head = new ListNode(0,head); // 充当头结点
        

        while(min_length < len){
            ListNode *pre = t_head, *curr = t_head->next;
            while(curr!=nullptr){
                ListNode *head1 = curr; // 第一个链表的头结点
                for(int i =1;i<min_length&&curr->next!=nullptr;i++){// 找到第一个子链的末尾
                    curr = curr->next;
                }
                ListNode *head2 = curr->next;// 第二个链表的头结点
                curr->next = nullptr; //将第一个链表的末尾设置为空
                curr = head2;
                for(int i =1;i<min_length&&curr!=nullptr&&curr->next!=nullptr;i++){// 找到第二个子链的末尾
                    curr = curr->next;
                }

                ListNode *next = nullptr;
                if(curr!=nullptr){ // 如果不是链表的结尾
                    next = curr->next; //保存后续进程的头结点
                    curr->next = nullptr;//将第二个链表的末尾设置为空
                }
                ListNode* merged = mergeTwoLists(head1, head2);
                pre->next = merged; // 保存已经有序的链表
                while (pre->next != nullptr) { // 进到以有序的链表的末尾
                    pre = pre->next;
                }
                curr = next; //下一次合并的链表的第一个结点
            }
            min_length <<=1; // min_length乘2
        }
        return t_head->next;


    }
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {  //力扣第21题. 合并两个有序链表
        ListNode* l =new  ListNode(0);
        ListNode* t = l;
        while(l1 != nullptr && l2!=nullptr){
            if(l1->val > l2->val){
                t->next = l2;
                
                l2 = l2->next;
            }else{
                t->next = l1;
                
                l1 = l1->next; 
            }
            t = t->next;
        }
        while(l1 != NULL){
                t->next = l1;
                t = t->next;
                l1 = l1->next; 
        }
        while(l2 != NULL){
                t->next = l2;
                t = t->next;
                l2 = l2->next;
        }
        return l->next;
    }    
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值