算法小知识-----04.23-----排序链表

93 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

快乐周末,虽然只有一天,但并不妨碍休息

排序链表

该题出自力扣的148题 —— 排序链表【中等题】

审题

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

image.png

  • 该题的题意并不是很复杂,简单来说就是给出一个链表的头结点,需要对链表进行排序后返回
  • 最初拿到这题的时候,想的是开辟一个额外的空间存储所有的节点,这样题目就变成了对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;
    }
}

image.png