148.排序链表

Posted magicya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了148.排序链表相关的知识,希望对你有一定的参考价值。

题目描述:

在 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 log n) 时间复杂度常数级空间复杂度,首先想到的就是快速排序和归并排序。
  此处使用归并排序,

  归并排序大致思想是: 1.将链表划分左右两部分--> 2.对左右链表进行排序 --> 3.将左右两个有序链表进行合并
  如果三个步骤如果分开实现的,都比较容易,但有人容易在第二步骤懵逼———为什么划分后,对左右链表进行排序,再合并,这不是多此一举么。直接使用第二步对原链表进行排序不就好了?
  
  所以,在归并排序中,实现第二步的实现,其实是靠第三部来完成的。
  当两个链表长度都为1时,即两个链表只有一个结点,那么我们就认为这两个链表是有序的,直接进行 步骤3——将两个有序链表进行合并,于是两个链表合并成了一个长度为2的有序链表。
  
  于是问题转化为,如何把一个长链表 划分为 长度为1的短链表? 很简单,递归划分,不断的将长链表进行二分,最终分成多个长度为1的链表,然后进行合并, 过程类似于二叉树。

  感觉和快速排序的分治思想没有太大区别。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        return head == null ? head : merge(head);  
    }
    //划分
    public ListNode merge(ListNode head){
        if (head.next == null) {  //递归退出条件:即链表被划分后只剩一个结点 
            return head;  
        }
        ListNode fast = head, slow = head, pre = head; //这里使用快慢指针 进行链表划分
        while (fast != null && fast.next != null) {
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        pre.next = null;     //划分结果是,fast为原链表尾.next, slow为划分后链表右半部分表头,pre为左半部分表尾结点,所以pre.next要为null
        ListNode l = merge(head); //左半部分递归划分 
        ListNode r = merge(slow); //右半部分递归划分
        return mergeList(l,r);  //合并链表 
    }
    //合并 此处f是合并两个有序链表。 
    public ListNode mergeList(ListNode h1,ListNode h2){
        ListNode dummy = new ListNode(0);
        ListNode head = dummy;
        while (h1 != null && h2 != null) {
            if (h1.val < h2.val) {
                head.next = h1;
                head = head.next;
                h1 = h1.next;
            }else {
                head.next = h2;
                head = head.next;
                h2 = h2.next;
            }
        }
        if (h1 == null) {
            head.next = h2;
        }else {
            head.next = h1;
        }
        return dummy.next;
    }
}

 

















以上是关于148.排序链表的主要内容,如果未能解决你的问题,请参考以下文章

148-链表排序

leetcode148 排序链表(Medium)

LeetCode Algorithm 148. 排序链表

[LeetCode] 148. 排序链表

LeetCode 148. 排序链表

LeetCode Java刷题笔记—148. 排序链表