Description:
Sort a linked list in O(n log n) time using constant space complexity
问题描述
给一条给定链表中的元素排序,返回排好序链表的头结点
限定条件
时间复杂度为O(nlogn) , 空间复杂度为O(1)
解法一:
思路:
看到时间复杂度为O(nlogn) , 应该想到归并排序和快排,这里给出归并排序的思路。
第一步:用快指针和慢指针将链表切分成两部分。最后prev指针落到前半部分的末尾处,slow指针落到后半部分的开头处。
第二步:对各个部分的链表分别进行归并排序(递归形式)操作
第三步:将排好序的链表进行合并操作,其中有如下四种情况的合并。
+ l1链表中的元素小于l2链表中的元素,取l1
+ l2链表中的元素小于l1链表中的元素,取l2
+ l1中的元素已经取完,取l2
+ l2中的元素已经取完 ,取l1
Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null)
return head;
//step1:将链表切分为两部分
ListNode prev = null;
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
prev.next = null;
//Step2:sort each half
ListNode l1 = sortList(head);
ListNode l2 = sortList(slow);
//Step3:Merge l1 and l2
return merge(l1,l2);
}
private ListNode merge(ListNode l1, ListNode l2){
ListNode dummy = new ListNode(0);
ListNode prev = dummy;
while(l1 != null && l2 != null){
if(l1.val < l2.val){
prev.next = l1;
l1 = l1.next;
}
else{
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
if(l1 != null)
prev.next = l1;
if(l2 != null)
prev.next = l2;
return dummy.next;
}
}
彩蛋:
归并排序是算法中分治思想的典型应用,在<<算法>>一书中对归并排序的过程有深刻阐述,只不过是以数组为例说明讲解,但是原理是想通的。