题解 | #单链表的排序#
单链表的排序
https://www.nowcoder.com/practice/f23604257af94d939848729b1a5cda08
关键在于归并排序的实用:
归并排序(Merge Sort)是一种分治法的经典应用,它通过将数组分成若干小部分,分别排序后再合并,最终得到一个有序的数组。这个算法的核心思想是“分而治之”,即将问题分解成更小的子问题,解决这些子问题后,再合并得到最终答案。
归并排序的步骤:
- 分割(Divide):将数组从中间位置不断地分成两部分,直到每部分只有一个元素为止。例如,给定一个长度为8的数组,我们会先将其分为两个长度为4的数组,然后再将这两个数组继续二分,直到每个子数组只有一个元素。
- 合并(Conquer):分割完成后,进入合并阶段。合并时,每次将两个有序的子数组合并成一个更大的有序数组。合并时通过比较两个数组的首元素,依次将较小的元素放入新数组中,直到所有元素合并完成。
- 递归回归(Combine):当最底层的子数组合并成更大的有序数组后,递归向上,逐步合并,直到最后生成一个有序的完整数组。
图文解释:
分割阶段:
假设我们有一个数组 [8, 3, 6, 2, 9, 1, 7, 4]。归并排序会首先将其分割成多个小数组:
[8, 3, 6, 2, 9, 1, 7, 4] => [8, 3, 6, 2] [9, 1, 7, 4] => [8, 3] [6, 2] [9, 1] [7, 4] => [8] [3] [6] [2] [9] [1] [7] [4]
合并阶段:
接着从最小的子数组开始,两两合并:
[8] [3] => [3, 8] [6] [2] => [2, 6] [9] [1] => [1, 9] [7] [4] => [4, 7] 接着合并: [3, 8] [2, 6] => [2, 3, 6, 8] [1, 9] [4, 7] => [1, 4, 7, 9] 最终合并: [2, 3, 6, 8] [1, 4, 7, 9] => [1, 2, 3, 4, 6, 7, 8, 9]
最终排序后的数组为 [1, 2, 3, 4, 6, 7, 8, 9]。
归并排序的特点:
- 时间复杂度:归并排序的时间复杂度为 O(n log n),即使在最坏情况下也能保持这个效率。
- 空间复杂度:由于在排序过程中需要额外的空间来存储中间结果,空间复杂度为 O(n)。
- 稳定性:归并排序是稳定的,即相同元素的相对顺序不会改变。
通过图示和上述步骤可以看出,归并排序的关键在于将数组分成小部分进行排序后再合并,而每次合并都是在有序的基础上进行,因此最终能得到一个有序数组。
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类 the head node
* @return ListNode类
*/
public ListNode sortInList (ListNode head) {
// write code here
// 链表为空或只有一个节点,直接返回
if (head == null || head.next == null) {
return head;
}
// 使用归并排序
// 先把链表分割成两部分,可以借助fast、slow 指针
ListNode fast = head;
ListNode slow = head;
ListNode prev = null; // 记录 slow 前面的节点,用来分割链表
while (fast != null && fast.next != null) {
prev = slow;
fast = fast.next.next;
slow = slow.next;
}
// 分割链表,前半部分为 head,后半部分为 slow
if (prev != null)
prev.next = null; // 断开前后部分
// 切割成最小颗粒度后合并
ListNode _left = sortInList(head);
ListNode _right = sortInList(slow);
return merge(_left, _right);
}
private ListNode merge(ListNode left, ListNode right) {
if (left == null) {
return right;
} else if (right == null) {
return left;
}
ListNode pHead = new ListNode(0);
ListNode dummy = pHead;
while (left != null || right != null) {
if (left == null) {
pHead.next = right;
break;
} else if (right == null) {
pHead.next = left;
break;
} else {
if (left.val < right.val) {
pHead.next = left;
left = left.next;
// pHead = left; // 要在主链上移动
} else {
pHead.next = right;
right = right.next;
// pHead = right; // 要在主链上移动
}
pHead = pHead.next; // 主链移动
}
}
return dummy.next;
}
}
查看7道真题和解析