LeetCode—148.排序链表(Sort List)——分析及代码(C++)

一、题目

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、分析及代码

1. 归并排序(优化后)

(1)思路

先运用二分法递归地对链表进行拆分,再依次将其按次序合并。
实现细节:
1)拆分时通过在子链表尾部添加空节点,断开原链表,便于归并时端点判断;
2)每个子链表归并结束时,也需在尾部添加空节点,避免尾部节点原 next 指针干扰;
3)二分法寻找中间节点时可结合双指针法。

(2)代码

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == NULL || head->next == NULL)
            return head;
        return mergeSort(head);
    }

    ListNode* mergeSort(ListNode* head) {
        if (head->next == NULL)//最小子链表为单个节点
            return head;        
        ListNode* head1 = head;
        ListNode* head2 = head->next;
        while (head2->next != NULL) {//双指针寻找中间节点
            head1 = head1->next;
            head2 = head2->next;
            if (head2->next != NULL) {
                head2 = head2->next;
            }
        }
        head2 = head1->next;//此处head2为子链表2的起始节点
        head1->next = NULL;//断开原链表
        ListNode* new_head1 = mergeSort(head);
        ListNode* new_head2 = mergeSort(head2);
        return merge(new_head1, new_head2);
    }

    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode* new_head;
        ListNode* node;
        ListNode* node1 = head1;
        ListNode* node2 = head2;
        if (head1->val < head2->val){//添加合并后的链表头部第一个节点
            new_head = head1;
            node1 = node1->next;
        }
        else {
            new_head = head2;
            node2 = node2->next;
        }
        node = new_head;
        while (node1 || node2) {//依次添加节点
            if (node1 && (!node2 || node1->val < node2->val)) {
                node->next = node1;
                node1 = node1->next;
            }
            else {
                node->next = node2;
                node2 = node2->next;
            }
            node = node->next;
        }
        node->next = NULL;//避免尾部节点原 next 指针干扰
        return new_head;
    }
};

(3)结果

执行用时 :48 ms, 在所有 C++ 提交中击败了 99.26% 的用户;
内存消耗 :11.6 MB, 在所有 C++ 提交中击败了 85.70% 的用户。

2. 归并排序(优化前)

(1)思路

最初未想到用空节点断开链表,选择计算链表长度进行辅助。

(2)代码

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == NULL || head->next == NULL)
            return head;
        int len = 0;
        ListNode* node = head;
        while (node != NULL) {
            len++;
            node = node->next;
        }
        return mergeSort(head, len);
    }

    ListNode* mergeSort(ListNode* head, int len) {
        if (len == 1)
            return head;        
        ListNode* head1 = head;
        ListNode* head2 = head;
        int len1 = 0, len2 = 0;
        while (len2 != len) {
            head1 = head1->next;
            len1++;
            head2 = head2->next;
            len2++;
            if (len2 != len) {
                head2 = head2->next;
                len2++;
            }
        }
        ListNode* new_head1 = mergeSort(head, len1);
        ListNode* new_head2 = mergeSort(head1, len - len1);
        return merge(new_head1, new_head2, len1, len - len1);
    }

    ListNode* merge(ListNode* head1, ListNode* head2, int len1, int len2) {
        int size1 = 0, size2 = 0;//已添加进新链表的长度
        ListNode* new_head;
        ListNode* node;
        ListNode* node1 = head1;
        ListNode* node2 = head2;
        if (head1->val < head2->val){
            new_head = head1;
            node1 = node1->next;
            size1++;
        }
        else {
            new_head = head2;
            node2 = node2->next;
            size2++;
        }
        node = new_head;
        while (size1 < len1 || size2 < len2) {
            if (size1 < len1 && (size2 == len2 || node1->val < node2->val)) {
                node->next = node1;
                node1 = node1->next;
                size1++;
            }
            else {
                node->next = node2;
                node2 = node2->next;
                size2++;
            }
            node = node->next;
        }
        node->next = NULL;
        return new_head;
    }
};

(3)结果

执行用时 :56 ms, 在所有 C++ 提交中击败了 90.46% 的用户;
内存消耗 :11.5 MB, 在所有 C++ 提交中击败了 93.69% 的用户。

三、其他

暂无。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值