题目
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
解答
解法一:归并排序
思路:
- 使用快慢指针确定中点的位置。
- 分别对左部分和右部分递归。
- merge 两部分链表。
要点:
- fast 指针的初始化:fast = head.next 这样可以保证取到中点的左边界。
- 归并过程分割次数:1,2,,,logn 次,可以看出分割次数是 O(logn) 级别。
- 快慢指针搜索次数:n / 2 * 1,n / 4 * 2 ,,,,n / (2^n) * (2^(n-1) )。可以看出是 O(n) 级别。
- merge 过程不多说了,不管使用递归还是非递归方式实现,时间复杂度都是 O(n) 级别 。
- merge 过程只使用到了几个指针(改变了一些指针的指向),空间复杂度是 O(1) 级别。
所以整体复杂度:
- O(nlogn) 的时间:【 分割次数 O(logn) x (快慢指针搜索次数 O(n) + merge 过程 O(n) ) 】= O(nlogn)
- O(1) 的空间:几个指针的交换 O(1)。(然而如果严格上来讲栈帧也是需要空间的 :)
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) return head;
ListNode slow = head;
ListNode fast = head.next;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode right = sortList(slow.next);
slow.next = null;
ListNode left = sortList(head);
return merge(left, right);
}
private 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(l1, l2.next);
return l2;
}
}
}
结果
解法二:快速排序
根据 pivot 将将链表分成两部分,分别进行快速排序。
复杂度:O(nlogn) 的时间,O(1) 的空间。
但能明显看出:链表还是适用于归并排序,并不适合用于快速排序。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
quickSort(head, null);
return head;
}
private void quickSort(ListNode head, ListNode tail) {
if(head == tail || head.next == tail) return;
int pivot = head.val;
ListNode left = head;
ListNode cur = head.next;
while(cur != tail) {
if(cur.val < pivot) {
left = left.next;
swapVal(left, cur);
}
cur = cur.next;
}
swapVal(head, left);
quickSort(head, left);
quickSort(left.next, tail);
}
private void swapVal(ListNode n1, ListNode n2) {
int t = n1.val;
n1.val = n2.val;
n2.val = t;
}
}