题目描述
题目链接: 148. 排序链表.
题解
递归方法归并排序,要求时间复杂度为O(nlogn)则想到二分法,继而想到归并排序。归并排序分为两个步骤,切分和归并。
1、切分
- 切分要找到中点,所以我们可以使用快慢指针找到链表的中点,断开链表。
- 递归切分前面的链表和后面的链表
- 递归终止条件,当然是不需要切分时终止,即
head == null
或者head.next == null
2、归并
- 双指针合并两个链表。
详见代码注释
class Solution {
public ListNode sortList(ListNode head) {
//终止条件,没有节点或者一个节点就不需要排序了
if (head == null || head.next == null) return head;
//快慢指针找到链表中点
ListNode fast = head, slow = head;
while (fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
}
//从中间断开
ListNode rHead = slow.next;
slow.next = null;
//递归处理前后两个链表
ListNode left = sortList(head);
ListNode right = sortList(rHead);
//连个链表处理完,进行合并
return merge(left, right);
}
public ListNode merge(ListNode left, ListNode right){
if (left == null) return right;
if (right == null) return left;
//res为哑节点,方便处理链表。 resTail为res的尾指针,用来插入节点
ListNode res = new ListNode(), resTail = res;
//left和right哪个小就接入res
while (left != null && right != null){
if (left.val < right.val){
resTail.next = left;
left = left.next;
}else{
resTail.next = right;
right = right.next;
}
resTail = resTail.next;
}
//最后如果两个链表还有剩余
if (left != null) resTail.next = left;
if (right != null) resTail.next = right;
//返回结果
return res.next;
}
}