LeetCode.148 排序链表

方法一:自顶向下的归并排序(递归法)

1. 分割:找到当前链表中点,并从中点将链表断开(以便下次递归时,链表片段拥有正确边界);

  • 首先对链表进行分割,使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点,对链表进行断开。
  • 找到重点slow后,执行slow.next = null 将链表切断
  • 递归分割时,输入当前链表左端点head和中心节点slow.next(因为链表是从slow切断的)
  • 终止条件:head.next = null时,说明只有一个节点了,直接返回此节点。

2.合并(merge):将两个排序链表合并,转化为一个排序链表。

 

该方法的时间复杂度为O(nlogn),空间复杂度因为使用了递归的方法所以应该为O(n)

 

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode() {}
 7  *     ListNode(int val) { this.val = val; }
 8  *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 9  * }
10  */
11 class Solution {
12     public ListNode sortList(ListNode head) {
13         if(head == null || head.next == null) return head;
14         ListNode slow = head, fast = head.next;
15         while(fast != null && fast.next != null){
16             slow = slow.next;
17             fast = fast.next.next;
18         }
19         ListNode temp = slow.next;
20         slow.next = null;
21         ListNode left = sortList(head);
22         ListNode right = sortList(temp);
23         ListNode h = new ListNode();
24         ListNode res = h;
25         while(left != null && right != null){
26             if(left.val <= right.val){
27                 res.next = left;
28                 left = left.next;
29             }else{
30                 res.next = right;
31                 right = right.next;
32             }
33             res = res.next;
34         }
35         res.next = left == null ? right : left;
36         return h.next;
37     }
38 }

方法二:自底向上归并排序

使用自底向上的方法实现归并排序,则可以达到 O(1)O(1) 的空间复杂度。

首先求得链表的长度 \textit{length}length,然后将链表拆分成子链表进行合并。

具体做法如下。

用 subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。

每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于  subLength×2)。合并两个子链表仍然使用「21. 合并两个有序链表」的做法。

将 subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。

如何保证每次合并之后得到的子链表都是有序的呢?可以通过数学归纳法证明。

初始时 subLength=1,每个长度为 11 的子链表都是有序的。

如果每个长度为 subLength 的子链表已经有序,合并两个长度为 subLength 的有序子链表,得到长度为 subLength×2 的子链表,一定也是有序的。

当最后一个子链表的长度小于 subLength 时,该子链表也是有序的,合并两个有序子链表之后得到的子链表一定也是有序的。

因此可以保证最后得到的链表是有序的。

 1 class Solution {
 2     public ListNode sortList(ListNode head) {
 3         if (head == null) {
 4             return head;
 5         }
 6         int length = 0;
 7         ListNode node = head;
 8         while (node != null) {
 9             length++;
10             node = node.next;
11         }
12         ListNode dummyHead = new ListNode(0, head);
13         for (int subLength = 1; subLength < length; subLength <<= 1) {
14             ListNode prev = dummyHead, curr = dummyHead.next;
15             while (curr != null) {
16                 ListNode head1 = curr;
17                 for (int i = 1; i < subLength && curr.next != null; i++) {
18                     curr = curr.next;
19                 }
20                 ListNode head2 = curr.next;
21                 curr.next = null;
22                 curr = head2;
23                 for (int i = 1; i < subLength && curr != null && curr.next != null; i++) {
24                     curr = curr.next;
25                 }
26                 ListNode next = null;
27                 if (curr != null) {
28                     next = curr.next;
29                     curr.next = null;
30                 }
31                 ListNode merged = merge(head1, head2);
32                 prev.next = merged;
33                 while (prev.next != null) {
34                     prev = prev.next;
35                 }
36                 curr = next;
37             }
38         }
39         return dummyHead.next;
40     }
41 
42     public ListNode merge(ListNode head1, ListNode head2) {
43         ListNode dummyHead = new ListNode(0);
44         ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
45         while (temp1 != null && temp2 != null) {
46             if (temp1.val <= temp2.val) {
47                 temp.next = temp1;
48                 temp1 = temp1.next;
49             } else {
50                 temp.next = temp2;
51                 temp2 = temp2.next;
52             }
53             temp = temp.next;
54         }
55         if (temp1 != null) {
56             temp.next = temp1;
57         } else if (temp2 != null) {
58             temp.next = temp2;
59         }
60         return dummyHead.next;
61     }
62 }

 

posted @ 2021-07-13 22:24  雪之下。  阅读(53)  评论(0)    收藏  举报