刷题148. Sort List

一、题目说明

题目148. Sort List,对链表进行排序,时间复杂度要求是O(nlog(n)),空间复杂度要求是常量。难度是Medium!

二、我的解答

根据要求,唯一符合标准的是归并排序。

class Solution{
    public:
        ListNode* sortList(ListNode* head){
            if(head==NULL || head->next==NULL) return head;
            return mergeSort(head);
        }
        //归并排序
        ListNode* mergeSort(ListNode* node){
            if(node==NULL || node->next==NULL) return node;
            ListNode* fast= node,*slow = node;
            ListNode* breakNode = node;//breakNode 指向l1的最后一个元素
            //也可以采用先遍历一遍,统计链表节点的数量,然后归并排序
            //找到链表中间
            while(fast && fast->next){
                fast = fast->next->next;
                breakNode = slow;
                slow = slow->next;
            }
            breakNode->next = NULL;
            ListNode* l1 = mergeSort(node);
            ListNode* l2 = mergeSort(slow);

            return merge(l1,l2);
        } 

        //合并两个链表 recursive
        ListNode* merge(ListNode* l1,ListNode* l2){
            if(l1 == NULL){
                return l2;
            }
            if(l2 == NULL){
                return l1;
            }
            if(l1->val < l2->val){
                l1->next = merge(l1->next,l2);
                return l1;
            }else{
                l2->next = merge(l2->next,l1);
                return l2;
            }
        }
};

性能如下:

Runtime: 60 ms, faster than 41.32% of C++ online submissions for Sort List.
Memory Usage: 16.2 MB, less than 15.00% of C++ online submissions for Sort List.

三、优化措施

将merge函数,修改为非递归版本:

class Solution{
    public:
        ListNode* sortList(ListNode* head){
            if(head==NULL || head->next==NULL) return head;
            return mergeSort(head);
        }
        //归并排序
        ListNode* mergeSort(ListNode* node){
            if(node==NULL || node->next==NULL) return node;
            ListNode* fast= node,*slow = node;
            ListNode* breakNode = node;//breakNode 指向l1的最后一个元素
            //找到链表中间
            while(fast && fast->next){
                fast = fast->next->next;
                breakNode = slow;
                slow = slow->next;
            }
            breakNode->next = NULL;
            ListNode* l1 = mergeSort(node);
            ListNode* l2 = mergeSort(slow);

            return merge(l1,l2);
        }
        //合并两个链表
        ListNode* merge(ListNode* l1,ListNode* l2){
            if(l1 == NULL) return l2;
            if(l2 == NULL) return l1;
            ListNode dummy(0);
            ListNode* p = &dummy;
            while(l1!=NULL && l2!=NULL){
                if(l1->val < l2->val){
                    p->next = l1;
                    l1 = l1->next;
                }else{
                    p->next = l2;
                    l2 = l2->next;
                }
                p = p->next;
            }
            if(l1 !=NULL){
                p->next = l1;
            }
            if(l2 !=NULL){
                p->next = l2;
            }
            return dummy.next;
        }
};

性能如下:

Runtime: 52 ms, faster than 67.44% of C++ online submissions for Sort List.
Memory Usage: 15 MB, less than 15.00% of C++ online submissions for Sort List.

原文地址:https://www.cnblogs.com/siweihz/p/12274559.html

时间: 2024-10-25 18:26:52

刷题148. Sort List的相关文章

刷题75. Sort Colors

一.题目说明 题目75. Sort Colors,给定n个整数的列表(0代表red,1代表white,2代表blue),排序实现相同颜色在一起.难度是Medium. 二.我的解答 这个是一个排序,还是简单的,代码如下: class Solution{ public: void sortColors(vector<int>& nums){ int num0=0,num1=0,num2=0; for(int i=0;i<nums.size();i++){ if(nums[i]==0)

【leetcode刷题笔记】Insertion Sort List

Sort a linked list using insertion sort. 题解:实现链表的插入排序. 要注意的地方就是,处理链表插入的时候尽量往当前游标的后面插入,而不要往前面插入,后者非常麻烦.所以每次利用kepeler.next.val和head.val比较大小,而不是kepeler.val和head.val比较大小,因为如果用后者,要把head指向的节点插入到kepeler指向的节点的前面,如果kepeler指向的节点是头结点,就更麻烦了. 代码如下: 1 /** 2 * Defi

【leetcode刷题笔记】Sort List

Sort a linked list in O(n log n) time using constant space complexity. 题解:实现一个链表的归并排序即可.主要分为三部分: 1.找到中点并返回的函数findMiddle; 2.归并函数merge; 3.排序函数sortList. 数组的findMiddle函数非常容易实现,链表就有一点tricky了.首先设置两个指针,一个slow初始化为head,一个fast初始化为head.next,然后slow一次走一步,fast一次走两

用js刷题的一些坑

leecode可以用js刷题了,我大js越来越被认可了是吧.但是刷题中会因为忽略js的一些特性掉入坑里.我这里总结一下我掉过的坑. 坑1:js中数组对象是引用对象 js中除了object还有数组对象也是引用对象,这点常常被忽视,所以在递归的时候传递数组要用arr.slice(0)这样复制一个一样的新数组,不然会出现你传入的数组会被同级的递归改变,结果就不对了. 所以只要数组复制的地方最好都要这么写,除非你真的想引用.而且注意是slice不是splice这两个方法差别很大,你如果用splice(0

Leetcode刷题录之Two Sum

题意大概是给出一个数列num,和一个目标数target,然后要找出数列中的两个数,使得这两个数之和等于目标数,输出这两个数的下标值(从1开始算). 一个比较暴力的方法是用一个二重循环直接遍历序列,在第一重循环中找到a,在第二重循环中找到b,使得a+b=target,这种做法的时间复杂度是O(n^2), 提交时提示超时. 改进方法,先对数列num复制一个副本,然后对副本进行排序.在一重循环中找到a,接着对这个有序的副本进行二分查找,找到b= target-a,二分查找的 时间复杂度是O(logn)

【leetcode刷题笔记】4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. Note: Elements in a quadruplet (a,b,c,d) must be in non-descending order.

【leetcode刷题笔记】Permutations II

Given a collection of numbers that might contain duplicates, return all possible unique permutations. For example,[1,1,2] have the following unique permutations:[1,1,2], [1,2,1], and [2,1,1]. 题解:跟Permutation差不多,只是这次会有重复的元素,如下图所示,如果只用DFS的话就会产生重复的排列: 上

洛谷 P1926 小书童——刷题大军

题目背景 数学是火,点亮物理的灯:物理是灯,照亮化学的路:化学是路,通向生物的坑:生物是坑,埋葬学理的人. 文言是火,点亮历史宫灯:历史是灯,照亮社会之路:社会是路,通向哲学大坑:哲学是坑,埋葬文科生.——小A 题目描述 小A“刷题”十分猖狂,明目张胆地“刷题”.他现在在小书童里发现了n样他喜欢的“题目”,每“题”都有他的需要时间,而老师布置了m项作业,每项作业都有它的需要时间及分值,老师规定k分以上算及格.小A只剩r个单位时间,他想在及格的基础上更多地“刷题”. 输入输出格式 输入格式: 第一

【leetcode刷题笔记】Merge Intervals

Given a collection of intervals, merge all overlapping intervals. For example,Given [1,3],[2,6],[8,10],[15,18],return [1,6],[8,10],[15,18]. 题解:首先对所有的区间按照start大小排序,然后遍历排序后的数组,用last记录前一个区间,如果遍历的当前区间可以和last合并,就把它合并到last里面:否则就把last放到answer list中,并且更新last