题目

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

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

示例

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

实现

思路1 归并排序

归并排序可以采用自顶向上或者是自顶向下。由于题目要求常数级空间复杂度,所以这里采用自底向上的方法。
image.png

  1. 首先将链表分割成长度为subLen的子链表(初始subLen=1),然后相邻两个子链表进行有序链表的合并(如第21题“合并两个有序链表”),这样就会得到若干个长度为subLen*2的有序子链表。
  2. 将subLen的值加倍然后重复上述循环,直到有序子链表的长度大于等于链表总长度,最终得到的就是排序好的链表。
  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. public:
  13. ListNode* sortList(ListNode* head) {
  14. if (head == nullptr) {
  15. return head;
  16. }
  17. // 1. 首先统计链表长度
  18. int length = 0;
  19. ListNode* node = head;
  20. while (node != nullptr) {
  21. length++;
  22. node = node->next;
  23. }
  24. // 2. 引入哨兵节点
  25. ListNode* dummyHead = new ListNode(0, head);
  26. // 3. 每次将链表拆分成若干个长度为subLen,两两归并
  27. for (int subLen = 1; subLen < length; subLen <<= 1) {
  28. // curr用来记录链表隔断的位置
  29. ListNode* prev = dummyHead, *curr = dummyHead->next;
  30. // 开始拆分整个链表
  31. while (curr != nullptr) {
  32. ListNode* head1 = curr; //第1个长度为subLen的链表头
  33. // 3.1 先拆分第1个长度为subLen的链表
  34. for (int i = 1; i < subLen && curr->next != nullptr; i++) {
  35. curr = curr->next;
  36. } // 找到第1个链表的尾部
  37. ListNode* head2 = curr->next; // 第2个链表的头,即链表1尾部的下一个节点
  38. curr->next = nullptr; // 断开第1个链表和第2个链表的连接
  39. curr = head2;
  40. // 3.2 再拆分第2个长度为subLen的链表
  41. for (int i = 1; i < subLen && curr != nullptr && curr->next != nullptr; i++) {
  42. curr = curr->next;
  43. } // 找到第2个链表的尾部
  44. // 断开第2个链表后面的连接
  45. ListNode* next = nullptr;
  46. if (curr != nullptr) {
  47. next = curr->next; // 用来记录两个链表的结束位置
  48. curr->next = nullptr;
  49. }
  50. // 3.3 合并前面拆分得到的两个subLen长度的有序链表
  51. ListNode* merged = mergeTwoLists(head1, head2);
  52. prev->next = merged;
  53. // 将prev移动到subLen*2位置后面,以开始下一轮的拆分
  54. while (prev->next != nullptr) {
  55. prev = prev->next;
  56. }
  57. curr = next;
  58. }
  59. }
  60. return dummyHead->next;
  61. }
  62. ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
  63. ListNode* head = new ListNode(-1); // 建立新的头用来保存合并后的链表
  64. ListNode* tail = head; // 记录新链表的尾部
  65. while(l1 != nullptr && l2 != nullptr) {
  66. if(l1->val < l2->val) {
  67. tail->next = l1;
  68. l1 = l1->next;
  69. } else {
  70. tail->next = l2;
  71. l2 = l2->next;
  72. }
  73. tail = tail->next;
  74. }
  75. // 遍历后l1和l2最多只有一个还未被合并完
  76. // 直接将链表末尾指向未合并完的链表即可
  77. if(l1 == nullptr) {
  78. tail->next = l2;
  79. } else {
  80. tail->next = l1;
  81. }
  82. return head->next;
  83. }
  84. };

时间复杂度:. 其中n是链表长度。
空间复杂度:.