一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
快乐周末,虽然只有一天,但并不妨碍休息
排序链表
该题出自力扣的148题 —— 排序链表【中等题】
审题
给你链表的头结点
head,请将其按 升序 排列并返回 排序后的链表 。
- 该题的题意并不是很复杂,简单来说就是给出一个链表的头结点,需要对链表进行排序后返回
- 最初拿到这题的时候,想的是开辟一个额外的空间存储所有的节点,这样题目就变成了对Map或者List的排序,当然了,最终没有这样实现,是因为用例超时了
- 解法:双指针 + 归并
- 简单带过一下归并,也就是分治法的一种,把问题拆分成子问题,排序后再合并
- 首先利用双指针对链表进行遍历
- 快慢指针,快指针快走两步,当快指针走到末尾的时候,慢指针刚好在中点
- 拿到链表的中点,也就意味着链表已经被切割成两段了
- 递归排序方法,把两端链表分别传进去
- 最终调用归并的方法 —— 也就是把两端有序的子链 合成一段有序的链表
- 定义一个全新的链表,并且给出一个初始值-1
- 遍历两段链表,其中一个更小就填充进新的链表
- 最终返回全新链表的next(跳过初始-1)
- 归并去处理链表方法会比较好,因为是稳定算法
编码
class Solution {
public ListNode sortList(ListNode head) {
//归并排序
return head == null? null :mergeSort(head);
}
public ListNode mergeSort(ListNode head){
//分
if (head == null || head.next == null)return head;
ListNode slow = head,fast = head.next.next,l,r;
while(fast!= null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
//对右边进行归并
r = mergeSort(slow.next);
slow.next = null;
l = mergeSort(head);
return merge(l,r);
}
public ListNode merge(ListNode l,ListNode r){
//治
ListNode tmpHead=new ListNode(-1);
ListNode p=tmpHead;
while (l!=null&&r!=null){
if (l.val<r.val){
p.next=l;
l=l.next;
}else {
p.next=r;
r=r.next;
}
p=p.next;
}
p.next=l==null?r:l;
return tmpHead.next;
}
}