目录
一,题目描述
英文描述
Given the head of a linked list, return the list after sorting it in ascending order.
中文描述
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例与说明
来源:力扣(LeetCode)
链接:力扣
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二,解题思路
官方给出的题解是归并排序。快速排序很明显会被针对。。。
归并排序的话,主要问题就是如何定位中间位置了。
定位
这里可以采用快慢指针的方法。
初始化在同一位置,快指针一次走两步,慢指针一次走一步。等快指针走到链表末尾,满指针所指节点的下一个节点就是中间位置。
链表合并
至于链表合并,这个比数组形式还要简单高效,毕竟不需要重开数组。
简单的方法就是声明一个空的头节点和指针p(该指针指向下一个节点要插入的位置),然后不断的移动左右链表的指针即可。
三,AC代码
Java
class Solution {
public ListNode merge (ListNode p1, ListNode p2) {
ListNode head = new ListNode(), p = head;
while (p1 != null && p2 != null) {
if (p1.val < p2.val) {
p.next = p1;
p1 = p1.next;
} else {
p.next = p2;
p2 = p2.next;
}
p.next.next = null;
p = p.next;
}
while (p1 != null) {
p.next = p1;
p1 = p1.next;
p.next.next = null;
p = p.next;
}
while (p2 != null) {
p.next = p2;
p2 = p2.next;
p.next.next = null;
p = p.next;
}
return head.next;
}
public ListNode mergeSort(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 p1 = mergeSort(slow.next);
slow.next = null; // 将链表分成两段
ListNode p2 = mergeSort(head);
return merge(p1, p2);
}
public ListNode sortList(ListNode head) {
return mergeSort(head);
}
}
四,解题过程
第一博
先尝试了简单的快速排序方法(选取head作为pivot)
class Solution {
public ListNode partation (ListNode head, ListNode left, ListNode right) {
if (head == null) return null;
ListNode pivot = head,p = head.next, tem;// 选取头节点作为pivot
while (p != null) {
tem = p;
p = p.next;
if (tem.val < pivot.val) {
tem.next = left.next;
left.next = tem;
} else {
tem.next = right.next;
right.next = tem;
}
}
return pivot;
}
public ListNode quickSort(ListNode head) {
if (head == null) return null;
ListNode left = new ListNode(), right = new ListNode();
ListNode mid = partation(head, left, right);
ListNode newLeft = quickSort(left.next);// 递归处理左半部分
ListNode newRight = quickSort(right.next);// 递归处理右半部分
// 将左半部分、pivot、右半部分进行合并
if (newLeft != null) {
ListNode tem = newLeft;
while (tem.next != null) tem = tem.next;
if (mid != null) {
tem.next = mid;
tem = tem.next;
}
tem.next = newRight;
} else if (mid != null) {
newLeft = mid;
newLeft.next = newRight;
} else {
newLeft = newRight;
}
return newLeft;
}
public ListNode sortList(ListNode head) {
return quickSort(head);
}
}
果然如此。。。妥妥的针对
第二搏
快慢指针+有序链表合并,轻车熟路了