1. 题目
原题链接
给你链表的头结点 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
Related Topics 排序 链表
👍 933 👎 0
2. 题解
2.1 解法 1
解法1 : 自顶向下递归
- 通过快慢指针法找到链表中点
- 分别对两个链表进行排序 (递归调用)
- 合并两个有序链表
递归的终止条件: 当链表节点数量为 0 或 链表中只有一个节点
注意点:
1、终止条件为 head == null || head.next == null
2、合并两个有序链表时,有cur = cur.next 别忘了
/**
* 解法1 : 自顶向下递归
* 1. 通过快慢指针法找到链表中点
* 2. 分别对两个链表进行排序 (递归调用)
* 3. 合并两个有序链表
* <p>
* 递归的终止条件:
* 当链表节点数量为 0 或 链表中只有一个节点
*/
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 mid = slow.next;
slow.next = null;
ListNode list1 = sortList(head);
ListNode list2 = sortList(mid);
ListNode temp = merge(list1, list2);
return temp;
}
/**
* 合并两个有序链表
*
* @param l1
* @param l2
* @return
*/
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode temp = dummy, p1 = l1, p2 = l2;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
temp.next = p1;
p1 = p1.next;
} else {
temp.next = p2;
p2 = p2.next;
}
temp = temp.next;
}
temp.next = p1 == null ? p2 : p1;
return dummy.next;
}
}
解法2
/**
* 解法2 : 自底向上迭代
* 1. 先获取链表长度, 然后每次先分块
* 2. 每次先分割两块, 然后进行合并
* 3. 之后再次循环, 增大步长, 直到步长大于等于链表长度, 排序结束
*/
class Solution {
public ListNode sortList(ListNode head) {
if (head == null) {
return null;
}
int len = getLength(head); // 获取链表长度
ListNode dummy = new ListNode(Integer.MIN_VALUE, head);// 设置一个哑结点
// 开始迭代, 每次迭代 步长翻倍, 终止条件为步长大于或等于链表长度
for (int step = 1; step < len; step = step * 2) {
// 每次迭代都要从头开始
ListNode prev = dummy, curr = dummy.next;
while (curr != null) { //开始每次的小合并
ListNode h1 = curr;
ListNode h2 = split(curr, step);
curr = split(h2, step); // 剩余部分的头
ListNode temp = merge(h1, h2);// 保存合并后的链表头
prev.next = temp; // 将本次合并的结果与前面部分的结果链接
while (prev.next != null) {
prev = prev.next;
}
}
}
return dummy.next;
}
public int getLength(ListNode head) {
if (head == null) {
return 0;
}
ListNode temp = head;
int len = 0;
while (temp != null) {
temp = temp.next;
len++;
}
return len;
}
/**
* 切分链表 , 返回切分后后一个链表的头结点
*
* @param head
* @return
*/
public ListNode split(ListNode head, int len) {
if (head == null) {
return null;
}
ListNode curr = head;
// 由于断链必须找到切割的前半部分的尾部节点
// 所以需要使 len!=1 而不是 0
while (len != 1 && curr != null) {
curr = curr.next;
len--;
}
if (curr == null) { // 注意出现长度不够导致curr=null 的情况
return null;
} else {
ListNode right = curr.next;
curr.next = null;// 断链
return right;
}
}
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode temp = dummy, p1 = l1, p2 = l2;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
temp.next = p1;
p1 = p1.next;
} else {
temp.next = p2;
p2 = p2.next;
}
temp = temp.next;
}
temp.next = p1 == null ? p2 : p1;
return dummy.next;
}
}
参考题解:
题解