148. 排序鏈表
阿新 • • 發佈:2019-05-12
return tlist 時間復雜度 並排 返回 listnode 數組 輸入 link
主要考察3個知識點,
知識點1:歸並排序的整體思想
知識點2:找到一個鏈表的中間節點的方法
知識點3:合並兩個已排好序的鏈表為一個新的有序鏈表
題目描述
在 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) ,所以想到了歸並排序和快排,但是這兩個都是針對數組的,用鏈表來實現就有點難了。
歸並排序法:在動手之前一直覺得空間復雜度為常量不太可能,因為原來使用歸並時,都是 O(N)的,需要復制出相等的空間來進行賦值歸並。對於鏈表,實際上是可以實現常數空間占用的(鏈表的歸並排序不需要額外的空間)。利用歸並的思想,遞歸地將當前鏈表分為兩段,然後merge,分兩段的方法是使用 fast-slow 法,用兩個指針,一個每次走兩步,一個走一步,知道快的走到了末尾,然後慢的所在位置就是中間位置,這樣就分成了兩段。merge時,把兩段頭部節點值比較,用一個 p 指向較小的,且記錄第一個節點,然後 兩段的頭一步一步向後走,p也一直向後走,總是指向較小節點,直至其中一個頭為NULL,處理剩下的元素。最後返回記錄的頭即可。
知識點1:歸並排序的整體思想
知識點2:找到一個鏈表的中間節點的方法
知識點3:合並兩個已排好序的鏈表為一個新的有序鏈表
貼出代碼
/** * 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 ? null : mergeSort(head); } private ListNode mergeSort(ListNode head){ if(head.next == null){ return head; } ListNode p = head, q = head, pre = null; while(q != null && q.next != null){ pre = p; p = p.next; q = q.next.next; } pre.next = null; ListNode l = mergeSort(head); ListNode r = mergeSort(p); return merge(l,r); } private ListNode merge(ListNode l, ListNode r){ ListNode dummy = new ListNode(0); ListNode curr = dummy; while(l != null && r != null){ if(l.val <= r.val){ curr.next = l; curr = curr.next; l = l.next; }else{ curr.next = r; curr = curr.next; r = r.next; } } if(l != null){ curr.next = l; } if(r != null){ curr.next = r; } return dummy.next; } }
148. 排序鏈表