题目
- 排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
提示:
链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105
题解
方法一:归并排序(递归法)
思路:在链表中点将链表断开,使用快慢指针法,找到中点后,输入当前链表左端点和中心端点,递归执行,当只有一个节点时,直接返回此节点
合并环节:将两个排序的链表进行合并,转化为一个排序链表
public ListNode sortList(ListNode head) {
// 1、递归结束条件
if (head == null || head.next == null) {
return head;
}
// 2、找到链表中间节点并断开链表 & 递归下探
ListNode midNode = middleNode(head);
ListNode rightHead = midNode.next;
midNode.next = null;
ListNode left = sortList(head);
ListNode right = sortList(rightHead);
// 3、当前层业务操作(合并有序链表)
return mergeTwoLists(left, right);
}
// 找到链表中间节点(876. 链表的中间结点)
private ListNode middleNode(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
// 合并两个有序链表(21. 合并两个有序链表)
private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode sentry = new ListNode(-1);
ListNode curr = sentry;
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 ? l1 : l2;
return sentry.next;
}
复杂度分析:
时间复杂度:O(nlogn)
空间复杂度:O(logn)
方法二:归并排序(从低至顶直接合并)
思路:使用迭代替换递归方法
class Solution {
public ListNode sortList(ListNode head) {
ListNode h, h1, h2, pre, res;
h = head;
int length = 0, intv = 1;
while (h != null) {
h = h.next;
length++;
}
res = new ListNode(0);
res.next = head;
while (intv < length) {
pre = res;
h = res.next;
while (h != null) {
int i = intv;
h1 = h;
while (i > 0 && h != null) {
h = h.next;
i--;
}
if (i > 0) break;
i = intv;
h2 = h;
while (i > 0 && h != null) {
h = h.next;
i--;
}
int c1 = intv, c2 = intv - i;
while (c1 > 0 && c2 > 0) {
if (h1.val < h2.val) {
pre.next = h1;
h1 = h1.next;
c1--;
} else {
pre.next = h2;
h2 = h2.next;
c2--;
}
pre = pre.next;
}
pre.next = c1 == 0 ? h2 : h1;
while (c1 > 0 || c2 > 0) {
pre = pre.next;
c1--;
c2--;
}
pre.next = h;
}
intv *= 2;
}
return res.next;
}
}
复杂度分析:
时间复杂度:O(nlogn)
空间复杂度:O(1)