【LeetCode 148】链表的归并排序

本文介绍了一种在O(nlogn)时间内使用常数空间复杂度对链表进行排序的方法。通过使用快慢指针技巧找到中间节点,将链表分为两部分,递归地进行排序,最后使用mergeTwoLists函数合并两个已排序的链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章用数组实现了二路归并排序,核心在于要对每次减半的元素进行实质性的改变,在数组中我们用临时数组记录每次merge的结果,在链表中用归并排序更加直接,因为我们操作的是结点的指针。

题目描述

难度:中等

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

Example 1:

Input: 4->2->1->3
Output: 1->2->3->4

Example 2:

Input: -1->5->3->4->0
Output: -1->0->3->4->5
题解
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode(-1);
        ListNode* cur = dummy;
        while (l1 && l2) {
            if (l1->val < l2->val) {
                cur->next = l1;
                cur = l1;
                l1 = l1->next;
                
            } else {
                cur->next = l2;
                cur = l2;
                l2 = l2->next;   
            }
        }
        
        if (l1) {
            cur->next = l1;
        } 
        if (l2) {
            cur->next = l2;
        }
        
        return dummy->next;
    }
    ListNode* sortList(ListNode* head) {
        // 归并排序,找到中间结点的方法是:快慢指针
        if (!head || !head->next) {
            return head;
        }
        ListNode* fast = head, *slow = head;
        // 奇数个元素时,slow结束时指向中间元素
        // 偶数个元素时,slow结束时指向前半段的最后一个元素,所以需要slow = slow->next
        while (fast->next && fast->next->next) {
            fast = fast->next->next;
            slow = slow->next;
        }
        
        // 断开成两部分
        fast = slow;
        slow = slow->next;
        fast->next = nullptr;
        
        ListNode* l1 = sortList(head);
        ListNode* l2 = sortList(slow);
        return mergeTwoLists(l1, l2);   
    }
};

在数组中计算中间点的方法是直接用下标计算,如果能够解决链表中的这个问题,则归并排序就很自然了。

回想一下快慢指针的功效,让快指针比慢指针速度快一倍,那么等快指针都跑完了,则慢指针才跑一半。

链表本身的长度是有限的,所以这个方法很可行。

找到中间点以后,需要把链表打断,调用merge即可,关于递归,在前文讲了一些思考(https://blog.csdn.net/u011240016/article/details/87903240),这里不再赘述。

PS. 想起实现这段代码时更新cur = l1时位置放在了l1 = l1->next后面导致的空指针问题。对于指针问题,需要特别注意操作的顺序,一点点的顺序错位,都会导致完全不同的结果。

END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值