1. 程式人生 > >148.排序鏈表

148.排序鏈表

sin code 二叉樹 color == 只有一個 pan init 問題

題目描述:

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.排序鏈表