每天一道LeetCode-----链表排序,要求复杂度在O(nlogn)

Sort List

原题链接Sort List

这里写图片描述

要求在O(nlogn)的时间复杂度下排序链表,且时间复杂度在O(1)

涉及到O(logn)的算法有

  • 二分法
  • 快速排序
  • 归并排序

二分法通常应用在已排序的序列中,且常用语查找算法,而不用作排序算法

快速排序需要从两边向中间逼近,对待链表而言同样不现实

归并排序类似于二分,不断切分已有序列再合并成一个有序序列,排序操作集中在合并过程中且通常是将两个有序序列合并成一个

综上,归并排序是适用于对链表的排序算法,算法流程如下

  1. 找到当前链表的中点,可以通过walker,runner指针的方法定位链表中部位置
  2. 将已有链表分成左右两部分分别作为独立的链表继续切分,直到链表只有一个节点或为nullptr时返回
  3. 在返回的过程中将左右两部分(有序)合并成一个有序链表,继续向上返回
  4. 最后得到排序后的链表

代码如下:

/**
 * 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 == nullptr || head->next == nullptr)
            return head;
        /* 找到链表中间的节点,prev代表中间节点的前一个节点 */
        ListNode* walker = head;
        ListNode* runner = head;
        ListNode* prev = nullptr;
        while(runner && runner->next)
        {
            prev = walker;
            walker = walker->next;
            runner = runner->next->next;
        }

        prev->next = nullptr;
        /* 此时head被分成两部分,head->prev->nullptr是一个,walker->nullptr是一个 */
        /* 对左右两部分分别进行切分和排序 */
        ListNode* lhs = sortList(head);
        ListNode* rhs = sortList(walker);
        /* 返回的lhs和rhs是已经排好序的链表,接下来将这两个有序链表合并成一个 */
        return mergeSort(lhs, rhs);
    }
private:
    /* 归并排序,将两个有序链表合并成一个 */
    ListNode* mergeSort(ListNode* lhs, ListNode* rhs)
    {
        ListNode* header = new ListNode(-1);
        ListNode* cur = header;
        while(lhs || rhs)
        {
            ListNode* next = nullptr;
            if(lhs == nullptr)
            {
                next = rhs;
                rhs = rhs->next;
            }
            else if(rhs == nullptr)
            {
                next = lhs;
                lhs = lhs->next;
            }
            else if(lhs->val > rhs->val)
            {
                next = rhs;
                rhs = rhs->next;
            }
            else
            {
                next = lhs;
                lhs = lhs->next;
            }
            next->next = nullptr;
            cur->next = next;
            cur = next;
        }
        cur = header->next;
        delete header;
        return cur;
    }
};

Sort Colors

原题链接Sort Colors

这里写图片描述

给定一个数组,数组中的元素只有0,1,2三种,对数组进行排序,要求不能使用标准库的排序函数

数组中只有0,1,2三种数值,那么遍历一遍记录这三个数分别有多少,最后一次赋值即可(低配版的计数排序)

代码如下:

class Solution {
public:
    void sortColors(vector<int>& nums) {
        vector<int> counts(3, 0);
        for(int n : nums)
            ++counts[n];
        int n = 0;
        for(int i = 0; i < 3; ++i)
        {
            for(int j = 0; j < counts[i]; ++j)
                nums[n++] = i;
        }
    }
};

上述两道题都是排序算法的类型,归并排序的时间复杂度是O(nlogn),并且适用于链表。而计数排序不是基于比较的排序算法,复杂度是O(k),k是待排序序列中元素的个数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值