【LeetCode148】链表排序

题目描述:

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5

提交结果

在这里插入图片描述

归并排序(最简单的)

虽然归并排序在对数组排序的时候空间复杂度为O(n),因为在merge的过程中会开辟一个长度为n的临时数组。但对两个有序链表的合并空间复杂度是O(1)的,只需将两条链表按照次序挂在一起即可,不需要辅助空间。

核心思想

和对数组的归并排序一样,分为三个过程

  • 将链表划分为两部分(二路归并)
  • 然后对分成的两部分采取同递归处理,直至不能再分(即只有一个结点,或者没有结点),因为此时每部分只有一个结点或者没有结点,所以每一部分都是有序的。
  • 进行有序链表的合并

注: 整个链表的排序过程以null,作为划分,而不再像数组那样有边界元素的索引作为界限。

具体操作
1.快慢指针法找中点

排序对象是链表,没有下标索引,因此需要通过遍历找中间结点,而快慢指针法只需一趟遍历即可找到中间结点。之前写得找中间结点的博客,也是LeetCode上的题目。快慢指针法找中点

2.递归调用mergeSortList
3.有序链表的合并

对于有序链表的合并,也是LeetCode上的题目,可分为递归解法和循环解法,也比较简单,可以参照之前写得合并有序链表的博客。合并有序链表.

代码实现

主体代码:

public ListNode mergeSortList(ListNode head) {
    // 空链表和一个结点的链表无需排序
    if(head == null || head.next == null){
        return head;
    }
    // 找中间结点
    ListNode midNode = findMid(head);
    // 左部分排序
    ListNode left = mergeSortList(head);
    // 右部分排序
    ListNode right = mergeSortList(midNode);
    // 合并
    ListNode newHead = merge(left,right);
    return newHead;
}

快慢指针找中间结点

private ListNode findMid(ListNode head){
    ListNode fast = head;
    ListNode slow = head;
    ListNode prev = null;
    while(fast != null && fast.next != null){
        prev = slow;
        slow = slow.next;
        fast = fast.next.next;
    }
    prev.next = null;    //   前半部分排序的划分界限
    return slow;
}

合并两个有序链表

private ListNode merge(ListNode left,ListNode right){
    if(left == null) return right;
    if(right == null) return left;
    ListNode head = null;
    if(left.val <= right.val){
        head = left;
        head.next = merge(left.next,right);
    }else{
        head = right;
        head.next = merge(left,right.next);
    }
    return head;
}

猜你喜欢

转载自blog.csdn.net/weixin_43213517/article/details/88765787
今日推荐