题目:
Sort a linked list in O(n log n) time using constant space complexity.
解题思路:
因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。
所以对应此题目,可以划分为三个小问题:
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
2)写出merge函数,即如何合并链表。 (见merge-two-sorted-lists 一题解析)
3)写出mergesort函数,实现上述步骤。
package leetcode;
public class Class_sortList {
public static ListNode createList() {
ListNode[] list = new ListNode[6];
int[] arr = { 1, 3, 2, 5, 4, 6 };
for (int i = 0; i < 6; i++) {
list[i] = new ListNode(arr[i]);
}
for (int i = 0; i < 5; i++) {
list[i].next = list[i + 1];
}
list[5].next = null;
return list[0];
}
/*
* 解题思路: 定义一快一慢的两个指针,快指针指向第二个节点,慢指针指向第一个节点;
* 慢指针一次走一步,快指针一次走两步,当快指针到达链表的尾部时,此时慢指针就是要找的中间节点。
*/
public static ListNode getMiddleListNode(ListNode pHead) {
if (pHead == null) {
return null;
}
ListNode pSlow = pHead;
ListNode pFast = pSlow.next;
while (pFast != null && pFast.next != null) {
pSlow = pSlow.next;
pFast = pFast.next.next;
}
return pSlow;
}
public static ListNode mergerLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
ListNode head = new ListNode(0);
ListNode p = head;
while (l1 != null && l2 != null) {
if (l1.val >= l2.val) {
p.next = l2;
l2 = l2.next;
} else {
p.next = l1;
l1 = l1.next;
}
p = p.next;
}
if (l1 != null) {
p.next = l1;
}
if (l2 != null) {
p.next = l2;
}
return head.next;
}
public static ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode mid = getMiddleListNode(head);
ListNode right = sortList(mid.next);
mid.next = null;
ListNode left = sortList(head);
return mergerLists(left, right);
}
public static void print(ListNode head) {
ListNode p = head;
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
}
public static void main(String[] args) {
ListNode head = createList();
ListNode res = sortList(head);
print(res);
}
}