题目描述
Sort a linked list in O(n log n)
time using constant space complexity.
以时间复杂度为O(n log n)和常量空间复杂度对链表进行排序。
解题思路
归并排序法:
利用归并的思想,递归地将当前链表分为两段,然后merge,分两段的方法是使用 fast-slow 法,用两个指针,一个每次走两步,一个走一步,直到快的走到了末尾,然后慢的所在位置就是中间位置,这样就分成了两段。merge时,把两段头部节点值比较,用一个 p 指向较小的,且记录第一个节点,然后 两段的头一步一步向后走,p也一直向后走,总是指向较小节点,直至其中一个头为NULL,处理剩下的元素。最后返回记录的头即可。
代码
public ListNode sortList(ListNode head) {
// 一个元素的情况
if (head == null || head.next == null)
return head;
return mergeSort(head);
}
/**
* 归并排序
*
* @param head
* @return
*/
public ListNode mergeSort(ListNode head) {
// 一个元素的情况
if (head == null || head.next == null)
return head;
ListNode fastNode = head;
ListNode slowNode = head;
ListNode preNode = null;
// 划分链表为两部分
while (fastNode != null && fastNode.next != null) {
fastNode = fastNode.next.next;
preNode = slowNode;
slowNode = slowNode.next;
}
if (preNode != null) {
preNode.next = null;
}
ListNode leftHalf = mergeSort(head);// 递归左半段
ListNode rightHalf = mergeSort(slowNode);// 递归右半段
return merge(leftHalf, rightHalf); // 归并
}
/**
* 归并两个已排好序的链表
*
* @param left
* @param right
* @return
*/
public ListNode merge(ListNode left, ListNode right) {
ListNode tempNode = new ListNode(0);
ListNode newHead = tempNode;// 新建一个虚拟头节点
while (left != null && right != null) {
if (left.val <= right.val) {
newHead.next = left;
left = left.next;
} else {
newHead.next = right;
right = right.next;
}
newHead = newHead.next;
}
if (left != null) {
newHead.next = left;
} else {
newHead.next = right;
}
newHead = tempNode.next;
tempNode.next = null;
tempNode = null;
return newHead;
}
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}