难度:Medium
题目:
给你链表的头结点
head
,请将其按 升序 排列并返回 排序后的链表 。
示例 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
进阶:你可以在 O(n log n)
时间复杂度和常数级空间复杂度下,对链表进行排序吗?
Related Topics
- 链表
- 双指针
- 分治
- 排序
- 归并排序
重点!!!解题思路
第一步:
明确解题手段:由于本章节练习归并排序所以这里是归并排序的写法
如果想看其他写法的请转移到这里LeetCode[148]排序链表
第二步:
由于是归并排序的写法,所以遵守归并排序的思路:先拆分递归再合并
拆分的时候要切断链表否则递归的时候出现循环链表错误
明白以上思路即可解题了
源码+讲解:
class Solution {
public ListNode sortList(ListNode head) {
int n=0; //获取此时链表长度
ListNode p=head;
while (p!=null){
p=p.next;
n++;
}
return merge_sort(head,n); //将链表长度作为参数进行传参
}
public ListNode merge_sort(ListNode head, int n) { //这里进行归并排序传参为头节点和链表长度
if (n<2) return head; //链表长度如果小于2那么就不要进行拆分了
int l_cnt=n/2,r_cnt=n-l_cnt; //获取左右两边链表的长度进行后续递归
ListNode p=head,l=head,r=head;
for (int i=0;i<l_cnt-1;i++){ //拆分链表需知道右边链表头节点的前一个节点,这样才能进行拆分
p=p.next;
}
r=p.next;
p.next=null;
l=merge_sort(l,l_cnt); //递归左边
r=merge_sort(r,r_cnt); //递归右边
ListNode ret=new ListNode(-1); //递归好后进行合并,合并的时候需要一个虚拟头节点进行辅佐操作
p=ret; //指定一个指针代替头节点移动
while (l!=null||r!=null){ //只要左右链表有值就继续操作
if (r==null || (l!=null&&l.val<r.val)){
p.next=l;
p=l;
l=l.next;
}else{
p.next=r;
p=r;
r=r.next;
}
}
return ret.next; //返回虚拟头节点的下一个节点即为结果
}
}
运行结果:
如果您还有什么疑问或解答有问题,可在下方评论,我会及时回复。
系列持续更新中,点个订阅吧,喜欢练习算法那就点个攒吧