持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
1、前言
每天一个算法小练习,本篇使用Java实现。
2、题目描述
给你链表的头结点 head ,请将其按升序排列并返回排序后的链表。
- 链表中节点的数目在范围 [0, 5 * 104] 内
- -105 <= Node.val <= 105
2.1、示例1
输入:head = [4,2,1,3]
输出:[1,2,3,4]
2.2、示例2
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
2.3、示例3
输入:head = []
输出:[]
3、解题思路
常用的排序算法有快排、选择、归并、插入、冒泡等,题目中进阶要求实现 时间复杂度和空间复杂度下排序。那么可选的就是快排、归并、堆排序。本体就非常适合使用归并排序来解决。
| 排序算法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 冒泡排序 | ||
| 选择排序 | ||
| 插入排序 | ||
| 快速排序 | 平均,最坏 | |
| 归并排序 | ||
| 堆排序 |
3.1、归并排序
归并排序就是将要排序的链表分成一个个的小链表,分而治之,再将每一排序好的小链表进行合并,得到有序链表。高效稳定,时间复杂度低。
public class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p = head;
int count = 0;
while (p != null) {
count++;
p = p.next;
}
return sortList(head, count);
}
public ListNode sortList(ListNode node, int nums) {
ListNode resNode = new ListNode(0);
if (node.next == null) {
return node;
}
ListNode left = node, r_pre = node, right = node;
int l_len = (nums + 1) / 2, r_len = nums- (nums + 1) / 2;
for (int i = 1; i < l_len; i++) {
r_pre = r_pre.next;
}
right = r_pre.next;
// 二分、递归,分别排序
r_pre.next = null;
left = sortList(left, l_len);
right = sortList(right, r_len);
resNode.next = left;
// p指向遍历过程中left的前一个元素
ListNode p = resNode;
while (left != null && right != null) {
if (left.val > right.val) {
r_pre = right;
right = right.next;
p.next = r_pre;
r_pre.next = left;
p = r_pre;
} else {
left = left.next;
p = p.next;
}
}
if (right != null) {
p.next = right;
}
return resNode.next;
}
}
执行结果:
-
时间复杂度:,n为链表的长度。
-
空间复杂度:
好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊