LeetCode148 - Sort List

本文详细解析了如何在链表数据结构中实现归并排序,以达到O(nlogn)的时间复杂度和O(1)的空间复杂度。通过设置快慢指针找到中间节点,递归地将链表分为两半,然后合并已排序的子链表。

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

Sort List 题目描述

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

即链表数据结构下的排序,且题目要求时间复杂度在O(n log n)以内,空间复杂度为常数O(1)

 

思路解析:

分析上述问题,要解决的有两点:

1. 链表数据的排序,而不是熟悉的数组排序;

2. 时间复杂度控制在O(n log n)以内,即需要熟悉常用的几种排序方式;

3. 空间复杂度为常数,即O(1),不允许使用额外的空间。

首先是链表排序,不能像数组一样随意的访问元素,链表需要从头往后撸。其次时间复杂度,常用的冒泡排序、选择排序、插入排序的时间复杂度为O (n^2),不满足要求。快速排序平均时间复杂度为O(n logn),最差为O(n^2),也不合适。再来看归并排序,时间复杂度为O(n log n),满足要求。空间复杂度,数组下的归并排序为O(n),即建立一个数组来存放排好的数。但在链表数据结构下,空间复杂度为O(1)。因为链表的节点从一开始给定后就不在变更,在排序过程中只是每个节点指向位置不同,即指针变化,而节点数不变。

通过上述分析,用归并排序解题。归并排序的核心思想就是找到数组,将原数组分开并递归此步骤,直到只有1个数时,开始比较排序并合并,即归并。在链表中也类似,从head节点往后撸,找到中间节点并把链表一分为二,递归此步骤。方法是撸链表时,设置快速指针fast和慢速指针slow,fast跑两步slow跑一步,当fast跑的最后一个节点时,slow到达middle处。递归上述步骤,归并时将节点重新排列

代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(!head || !head->next)    return head;
        
        // 找到列表中间指针
        ListNode *fast = head, *slow = head, *pre = head;
        while (fast && fast->next) {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = NULL;
        
        // 递归找到子列表中间指针,直到剩下一个列表
        ListNode* leftList = sortList(head);
        ListNode* rightList = sortList(slow);
        
        // 归并排序
        return mergeSort(leftList, rightList);
    }
    
    ListNode* mergeSort(ListNode* leftList, ListNode* rightList) {
        ListNode* result = new ListNode(-1);
        ListNode* cur = result;
        while (leftList || rightList) {
            int valL = (leftList == NULL) ? INT_MAX : leftList->val;
            int valR = (rightList == NULL) ? INT_MAX : rightList->val;
            
            if (valL <= valR) {
                cur->next = leftList;
                leftList = leftList->next;
            }
            else {
                cur->next = rightList;
                rightList = rightList->next;
            }
            cur = cur->next;
        }
        return result->next;
    }
};

学习内容:

1.  链表数据结构的再一次熟悉,如无new ListNode()代码便不生成新节点,没有额外空间。当使用ListNode* p创建新的链表指针时,并没有建立新节点没有增加额外空间,只是为了改变已有节点的指向。所以上述代码空间复杂度为O(1)。

2. 归并排序算法在链表数据结构中的使用

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值