Sort Listjava
Sort a linked list in O(n log n) time using constant space complexity.node
使用Merge Sort, 空間複雜度是 O(logN) 由於使用了棧空間。git
SOLUTION 1:github
使用Merge Sort來解決問題。ide
爲何不用QuickSort?
由於隨機訪問對於鏈表而言太耗時,而heap sort不可行。大數據
注意,Find Mid用了2種解法。或者是讓Fast提早結束,或是讓Fast先走一步,目的就是要取得中間節點的前一個。這樣作的目的,主要優化
是爲了解決:ui
1->2->nullspa
這一種狀況。若是不這麼作,slow會返回2.這樣咱們沒辦法切割2個Node的這種狀況。code
1 /** 2 * Definition for singly-linked list. 3 * class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { 7 * val = x; 8 * next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 public ListNode sortList(ListNode head) { 14 // Nodes should be more than 2. 15 if (head == null || head.next == null) { 16 return head; 17 } 18 19 // get the mid node. 20 ListNode midPre = getMidPre(head); 21 22 // Cut the two list. 23 ListNode right = midPre.next; 24 midPre.next = null; 25 26 // Sort the left side and the right side. 27 ListNode left = sortList(head); 28 right = sortList(right); 29 30 // Merge the two sides together. 31 return merge(left, right); 32 } 33 34 // get the pre node before mid. 35 public ListNode getMidPre1(ListNode head) { 36 ListNode slow = head; 37 ListNode fast = head; 38 39 while (fast != null && fast.next != null && fast.next.next != null) { 40 slow = slow.next; 41 fast = fast.next.next; 42 } 43 44 return slow; 45 } 46 47 // get the pre node before mid. 48 public ListNode getMidPre(ListNode head) { 49 ListNode slow = head; 50 51 // fast提早一點兒。這樣就能夠獲得前一個節點嘍。 52 ListNode fast = head.next; 53 54 while (fast != null && fast.next != null) { 55 slow = slow.next; 56 fast = fast.next.next; 57 } 58 59 return slow; 60 } 61 62 public ListNode merge(ListNode head1, ListNode head2) { 63 ListNode dummy = new ListNode(0); 64 ListNode cur = dummy; 65 66 while (head1 != null && head2 != null) { 67 if (head1.val < head2.val) { 68 cur.next = head1; 69 head1 = head1.next; 70 } else { 71 cur.next = head2; 72 head2 = head2.next; 73 } 74 75 cur = cur.next; 76 } 77 78 if (head1 != null) { 79 cur.next = head1; 80 } else { 81 cur.next = head2; 82 } 83 84 return dummy.next; 85 } 86 }
SOLUTION 2:
使用快排也能夠解決。可是注意,要加一個優化才能夠過大數據,就是判斷一下是否是整個鏈條是相同的節點,好比2 2 2 2 2 2 2 ,這樣的就直接掃一次不用執行
快排,不然它會是N平方的複雜度。
參考資料:
https://oj.leetcode.com/discuss/3577/i-use-quick-sort-to-sort-the-list-but-why-i-get-time-limited
1 /* 2 The Solution 2: 3 Quick Sort. 4 */ 5 public ListNode sortList(ListNode head) { 6 if (head == null) { 7 return null; 8 } 9 10 // Sort the list from 0 to len - 1 11 return quickSort(head); 12 } 13 14 // The quick sort algorithm 15 16 // All the elements are the same! 17 public boolean isDuplicate(ListNode head) { 18 while (head != null) { 19 if (head.next != null && head.next.val != head.val) { 20 return false; 21 } 22 23 head = head.next; 24 } 25 26 return true; 27 } 28 29 public ListNode quickSort(ListNode head) { 30 if (head == null) { 31 return null; 32 } 33 34 // 若是整個鏈是重複的,直接跳過。 35 if (isDuplicate(head)) { 36 return head; 37 } 38 39 // Use the head node to be the pivot. 40 ListNode headNew = partition(head, head.val); 41 42 // Find the pre position of the pivoit. 43 ListNode cur = headNew; 44 45 ListNode dummy = new ListNode(0); 46 dummy.next = headNew; 47 48 ListNode pre = dummy; 49 50 // Find the pre node and the position of the piviot. 51 while (cur != null) { 52 if (cur.val == head.val) { 53 break; 54 } 55 56 // move forward. 57 cur = cur.next; 58 pre = pre.next; 59 } 60 61 // Cut the link to be three parts. 62 pre.next = null; 63 64 // Get the left link; 65 ListNode left = dummy.next; 66 67 // Get the right link. 68 ListNode right = cur.next; 69 cur.next = null; 70 71 // Recurtion to call quick sort to sort left and right link. 72 left = quickSort(left); 73 right = quickSort(right); 74 75 // Link the three part together. 76 77 // Link the first part and the 2nd part. 78 if (left != null) { 79 dummy.next = left; 80 81 // Find the tail of the left link. 82 while (left.next != null) { 83 left = left.next; 84 } 85 left.next = cur; 86 } else { 87 dummy.next = cur; 88 } 89 90 cur.next = right; 91 92 // The new head; 93 return dummy.next; 94 } 95 96 // Return the new head; 97 public ListNode partition(ListNode head, int x) { 98 if (head == null) { 99 return null; 100 } 101 102 ListNode dummy = new ListNode(0); 103 dummy.next = head; 104 105 ListNode pre = dummy; 106 ListNode cur = head; 107 108 // Record the big list. 109 ListNode bigDummy = new ListNode(0); 110 ListNode bigTail = bigDummy; 111 112 while (cur != null) { 113 if (cur.val >= x) { 114 // Unlink the cur; 115 pre.next = cur.next; 116 117 // Add the cur to the tail of the new link. 118 bigTail.next = cur; 119 cur.next = null; 120 121 // Refresh the bigTail. 122 bigTail = cur; 123 124 // 移除了一個元素的時候,pre不須要修改,由於cur已經移動到下一個位置了。 125 } else { 126 pre = pre.next; 127 } 128 129 cur = pre.next; 130 } 131 132 // Link the Big linklist to the smaller one. 133 pre.next = bigDummy.next; 134 135 return dummy.next; 136 }
GITHUB:
https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/list/SortList.java