Sort a linked list in O(n log n) time using constant space complexity.
Example 1:
Input: 4->2->1->3
Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0
Output: -1->0->3->4->5
要求将列表排序,不适用额外的空间 且时间复杂度为
o(nlogn)
熟悉排序算法的话就知道要用到归并排序了,但在链表上直接进行归并排序的话还是要花一番功夫的。先看代码
public ListNode sortList(ListNode head) {
//head为空或者链表只有一个节点则直接返回
if(head == null || head.next == null) return head;
ListNode tail = head.next;
while (tail.next != null) {
tail = tail.next;
}
//进行归并排序
return mergeSortList(head,tail);
}
/**
* 对链表排序,分别对左右递归操作
* 如果begin == end 返回当前值
*
*/
public ListNode mergeSortList(ListNode begin,ListNode end){
if(begin == end){
begin.next = null;
return begin;
}
ListNode head = null;
ListNode end1 = getMidNode(begin, end);
ListNode begin2 = end1.next;
//左右排完序后两个链表的头节点
ListNode left = mergeSortList(begin,end1);
ListNode right = mergeSortList(begin2,end);
//选取头节点
if(left.val < right.val){
head = left;
left = left.next;
}else {
head =right;
right = right.next;
}
//设置当前指针
ListNode cur = head;
//合并两个链表
while(left != null && right != null){
if(left.val < right.val) {
cur.next = left;
left = left.next;
}else{
cur.next = right;
right = right.next;
}
cur = cur.next;
}
if(left != null) cur.next = left;
if(right != null) cur.next = right;
return head;
}
ListNode getMidNode(ListNode begin,ListNode end){
if(begin == end || begin.next == end) return begin;
ListNode slow = begin, fast = begin;
while(fast != end && fast.next != end){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
重点看函数public ListNode mergeSortList(ListNode begin,ListNode end)
这个函数就是将从begin开始到end的链表进行排序
无论end之后是否还有节点,排序完后我们都让这个链表成为一个独立的链表,即排序完最后的节点的下一个节点为空.
因此当一个链表的左右两端排序完成后我们就将原链表拆分成了两个完全独立的链表,这样之后合并就很方便了
ListNode getMidNode(ListNode begin,ListNode end)
就是获取链表中点了,没什么好说
再说一句,这题挺不错,复习了链表和归并排序