zoukankan      html  css  js  c++  java
  • leetcode 148. 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

    Example 3:

    Input: head = []
    Output: []
    

    Constraints:

    • The number of nodes in the list is in the range [0, 5 * 104].
    • -105 <= Node.val <= 105

    题目难度:简单(递归式归并),中等(非递归归并)

    题目大意:给一个链表排序,并要求常数空间复杂度$O(1)$,$O(nlogn)时间复杂度$

    思路:常用的快排和归并排序,快排在有些情况下的时间复杂度是$(n^2)$,在链表情况下不方便。选择第一个节点为枢纽值。

    归并排序时间复杂度是$O(nlogn)$,用递归方法实现的方法,空间复杂度是O(logn)(栈)。所以按照提议应该选择迭代式的归并排序,可以实现$O(1)$空间复杂度(由于是链表,在归并的时候可以不用先new数组作为辅助)。


    版本一:递归式的归并排序C++代码:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode() : val(0), next(nullptr) {}
     7  *     ListNode(int x) : val(x), next(nullptr) {}
     8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
     9  * };
    10  */
    11 class Solution {
    12 private:
    13     //合并两个有序链表
    14     ListNode* mergeList(ListNode *front, ListNode *rear) {
    15         ListNode *res = new ListNode(0), *tail = res;
    16         ListNode *tmp1 = front, *tmp2 = rear;
    17         while ((nullptr != tmp1) && (nullptr != tmp2)) {
    18             if (tmp1->val <= tmp2->val) {
    19                 tail->next = tmp1;
    20                 tail = tmp1;
    21                 tmp1 = tmp1->next;
    22             } else {
    23                 tail->next = tmp2;
    24                 tail = tmp2;
    25                 tmp2 = tmp2->next;
    26             }
    27             tail->next = NULL;
    28         }
    29         if (nullptr != tmp1)
    30             tail->next = tmp1;
    31         else
    32             tail->next = tmp2;
    33         return res->next;
    34     }
    35     //找到后一半链表,并返回后一半链表的头指针,同时将前一半链表的尾结点指针指向NULL。
    36     ListNode* splitList(ListNode *head) {
    37         ListNode *midPrev = head, *fast = head->next;
    38         //采用快慢指针的方法找到链表中点
    39         while ((nullptr != fast) && (nullptr != fast->next)) {
    40             fast = fast->next->next;
    41             midPrev = midPrev->next;
    42         }
    43         ListNode *mid = midPrev->next;
    44         midPrev->next = nullptr;
    45         return mid;
    46     }
    47     // void printList(ListNode *head) {
    48     //     if (nullptr == head) return;
    49     //     cout << head->val;
    50     //     ListNode *tmp = head->next;
    51     //     while (nullptr != tmp) {
    52     //         cout << "->" << tmp->val;
    53     //         tmp = tmp->next;
    54     //     }
    55     //     cout << endl;
    56     // }
    57 public:
    58     ListNode* sortList(ListNode* head) {
    59         if ((head == nullptr) || (head->next == nullptr)) return head;
    60         ListNode *rear = splitList(head); //找到后一半链表
    61         // printList(head);
    62         // printList(rear);
    63         ListNode *head1 = sortList(head); //将前一半链表排好序
    64         // printList(head1);
    65         ListNode *head2 = sortList(rear); //将后一半链表排好序
    66         // printList(head2);
    67         return mergeList(head1, head2); //合并两个排好序的链表,并返回。
    68     }
    69 };

    版本二:迭代式的归并排序C++代码:

     1 class Solution {
     2 private:
     3     ListNode* split(ListNode *start, int size) {
     4         ListNode* midPrev = start;
     5         ListNode* end = start->next;
     6         for (int index = 1; index < size && (midPrev->next || end->next); ++index) {
     7             if (end->next) {
     8                 end = (end->next->next) ? end->next->next : end->next;
     9             }
    10             if (midPrev->next) {
    11                 midPrev = midPrev->next;
    12             }
    13         }
    14         ListNode *mid = midPrev->next;
    15         nextSubList = end->next;
    16         midPrev->next = nullptr;
    17         end->next = nullptr;
    18         return mid;
    19     }
    20     
    21     //合并两个有序链表
    22     void mergeList(ListNode *front, ListNode *rear) {
    23         ListNode *res = new ListNode(0), *newTail = res;
    24         ListNode *tmp1 = front, *tmp2 = rear;
    25         while ((nullptr != tmp1) && (nullptr != tmp2)) {
    26             if (tmp1->val <= tmp2->val) {
    27                 newTail->next = tmp1;
    28                 newTail = tmp1;
    29                 tmp1 = tmp1->next;
    30             } else {
    31                 newTail->next = tmp2;
    32                 newTail = tmp2;
    33                 tmp2 = tmp2->next;
    34             }
    35             newTail->next = NULL;
    36         }
    37         if (nullptr != tmp1)
    38             newTail->next = tmp1;
    39         else
    40             newTail->next = tmp2;
    41         while (newTail->next) {
    42             newTail = newTail->next;
    43         }
    44         tail->next = res->next;
    45         tail = newTail;
    46     }
    47     int gCount(ListNode *head) {
    48         int cnt = 0;
    49         ListNode *tmp = head;
    50         while (nullptr != tmp) {
    51             ++cnt;
    52             tmp = tmp->next;
    53         }
    54         return cnt;
    55     }
    56     // void printList(ListNode *head) {
    57     //     if (nullptr == head) return;
    58     //     cout << head->val;
    59     //     ListNode *tmp = head->next;
    60     //     while (nullptr != tmp) {
    61     //         cout << "->" << tmp->val;
    62     //         tmp = tmp->next;
    63     //     }
    64     //     cout << endl;
    65     // }
    66 public:
    67     ListNode *tail = new ListNode(); //用于始终指向已排序部分的尾结点
    68     ListNode *nextSubList = new ListNode(); //始终指向待排序部分的头结点
    69     
    70     ListNode* sortList(ListNode* head) {
    71         if (!head || !head->next) return head;
    72         int sz = gCount(head);
    73         ListNode *start = head;
    74         ListNode *dummyHead = new ListNode(0);
    75         for (int size = 1; size < sz; size = size * 2) {
    76             tail = dummyHead;
    77             while (start) {
    78                 if (!start->next) {
    79                     tail->next = start;
    80                     break;
    81                 }
    82                 ListNode *mid = split(start, size);
    83                 mergeList(start, mid);
    84                 start = nextSubList;
    85             }
    86             start = dummyHead->next;
    87         }
    88         return dummyHead->next;
    89     }   
    90 };
  • 相关阅读:
    Win10 Theano Install Guide
    mysql 查看版本和是否支持分区
    [mysql]Date和String相互转换(DATE_FORMAT&STR_TO_DATE)
    mysql运用now(3)存储时间到毫秒
    mysql按天,按周,按月,按季度,按年统计数据
    对象的copy
    定时调度任务quartz
    mysql使用navicat编写调用存储过程
    mysql批量插入,批量更新
    Mybatis分页插件pagehelper的使用
  • 原文地址:https://www.cnblogs.com/qinduanyinghua/p/13664965.html
Copyright © 2011-2022 走看看