HOT33-排序链表

该文章介绍了一种使用归并排序思想解决LeetCode上的排序链表问题的方法。通过找到链表的中间节点,将链表一分为二,然后递归地对每个半部分进行排序,最后合并两个已排序的链表。这种方法的时间复杂度是O(nlogn),空间复杂度是O(1)。
摘要由CSDN通过智能技术生成

      leetcode原题链接排序链表

       Hot目录HOT目录

      上一篇HOT32-复制带随机指针的链表

      下一篇HOT34-合并K个升序链表

题目描述

      给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

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

示例 3:

输入:head = []
输出:[]

提示: 

  • 链表中节点的数目在范围 [0, 5 * 104] 内
  • -105 <= Node.val <= 105

进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

解题方法:类似数组的归并排序法。解题过程如下

1. 找到链表的中间节点。

2. 拆分链表,将原链表一分为二。

3. 分别对区间[head, mid]和[mid->next,tail]组成两个链表内部各自排序。

4. 将两个有序空间合并。

C++代码

#include <iostream>
#include <memory> //std::shared_ptr
/**
 * 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) {}
 *     1->2->3->4->5
 *.    1->2->3->4->5->6
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (!head || !head->next) { //空链表或者链表仅包含一个节点
            return head;
        }
        //1. 找到链表的中间节点
        ListNode* p_mid = get_mid_node(head);
        if (!p_mid) {
            return nullptr;
        }
        //2. 拆分链表,将原链表一分为二
        ListNode *head1 = p_mid->next;//获取后半部分的head节点
        p_mid->next = nullptr;//拆分前半部分
        //3. 分别对区间[head, mid], [mid->next,tail]排序
        head = sortList(head);//对左半部分排序
        head1 = sortList(head1);//对右半部分排序
        //4. 将两个有序空间合并
        return merge(head, head1);//返回合并后的链表
    }
    // 快慢指针获取链表的中间节点
    ListNode* get_mid_node(ListNode* head) {
        if (!head || !head->next) {
            return head;
        }
        ListNode* p1 = head;//一次走1步的慢指针
        ListNode* p2 = head;//一次走2步的快指针
        while (p2 && p2->next && p2->next->next) {
            p1 = p1->next;
            p2 = p2->next->next;
        }
        return p1;
    }
    // 合并两个有序的链表
    ListNode* merge(ListNode* head1, ListNode* head2) {
        if (!head1) {
            return head2;
        }
        if (!head2) {
            return head1;
        }
        std::shared_ptr<ListNode> dummy_node(new ListNode(0));
        ListNode* p = dummy_node.get();//用哨兵节点可以避免对新链表头节点单独判断
        ListNode* p1 = head1;
        ListNode* p2 = head2;
        while (p1 && p2) {
            if (p1->val <= p2->val) {
                p->next = p1;
                p1 = p1->next;
            } else {
                p->next = p2;
                p2 = p2->next;
            }
            p = p->next;
        }
        if (p1) { //head1更长
            p->next = p1;
        }
        if (p2) { //head2更长
            p->next = p2;
        }
        return dummy_node->next;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值