题目描述
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
输入输出样例
输入: 4->2->1->3
输出: 1->2->3->4
题解
这种中档难度的题目,考察的多个知识点的融合,所以基础需要牢牢把握。
- run 指针找到链表长度
- cut(ListNode head, int size) 切分链表
- merge(ListNode hA, ListNode hB) 合并链表
代码:
class Solution {
public ListNode sortList(ListNode head) {
// 得到链表的长度
ListNode runner = head;
int len = 0;
while(runner != null){
runner = runner.next;
len++;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
// 循环进行链表的拆分和合并
for(int size=1; size<len; size*=2){
ListNode curr = dummy.next;
ListNode tail = dummy;
while(curr != null){
ListNode left = curr;
// 第一次切割,left就变成了size长的链表了
ListNode right = cut(curr, size);
// 第二次切割,right就变成了size长的链表了
curr = cut(right, size);
// 对两个片段链表进行排序
tail.next = merge(left, right);
while(tail.next!=null){
tail = tail.next;
}
}
}
return dummy.next;
}
// 切分链表指定长度,并且返回后边链表的头部
public ListNode cut(ListNode head, int size){
ListNode p = head;
while(--size>0 && p != null){
p = p.next;
}
if(p==null) return null;
ListNode next = p.next;
p.next = null;
return next;
}
public ListNode merge(ListNode l1, ListNode l2){
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
while(l1!=null && l2!=null){
if(l1.val < l2.val){
curr.next = l1;
l1 = l1.next;
}else{
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = (l1 == null) ? l2:l1;
return dummy.next;
}
}
不符合题意的递归解法
思路和上面的基本一致。
不同点是上面的切分是自底而上地切分,递归则是每次找到中点,自顶而下地切分。
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 temp = slow.next;
slow.next = null;
// 递归两个链表
head = sortList(head);
temp = sortList(temp);
ListNode curr = new ListNode(0);
ListNode ret = curr;
// 递归完成之后,对两个有序列表进行组合
while(head != null && temp != null){
if(head.val <= temp.val){
curr.next = head;
curr = curr.next;
head = head.next;
}else{
curr.next = temp;
curr = curr.next;
temp = temp.next;
}
}
if(temp == null){
curr.next = head;
}
if(head == null){
curr.next = temp;
}
return ret.next;
}
}