給你鍊錶的頭結點 head ,請將其按 公升序 排列並返回 排序後的鍊錶 。
高階:
你可以在 o(n log n) 時間複雜度和常數級空間複雜度下,對鍊錶進行排序嗎?
題目分析:
要求使用插入排序的方法對鍊錶進行排序,插入排序的時間複雜度是 o(n^2),其中 nn 是鍊錶的長度。這道題考慮時間複雜度更低的排序演算法。題目的高階問題要求達到 o(nlogn) 的時間複雜度和 o(1) 的空間複雜度,時間複雜度是 o(nlogn) 的排序演算法包括歸併排序、堆排序和快速排序(快速排序的最差時間複雜度是 o(n^2)),其中最適合鍊錶的排序演算法是歸併排序。
歸併排序基於分治演算法。最容易想到的實現方式是自頂向下的遞迴實現,考慮到遞迴呼叫的棧空間,自頂向下歸併排序的空間複雜度是 o(logn)。如果要達到 o(1) 的空間複雜度,則需要使用自底向上的實現方式。
對鍊錶自頂向下歸併排序的過程如下。
找到鍊錶的中點,以中點為分界,將鍊錶拆分成兩個子鍊錶。尋找鍊錶的中點可以使用快慢指標的做法,快指標每次移動 2 步,慢指標每次移動 1 步,當快指標到達鍊錶末尾時,慢指標指向的鍊錶節點即為鍊錶的中點。
對兩個子鍊錶分別排序。
將兩個排序後的子鍊錶合併,得到完整的排序後的鍊錶。
上述過程可以通過遞迴實現。遞迴的終止條件是鍊錶的節點個數小於或等於 1,即當鍊表為空或者鍊錶只包含 1 個節點時,不需要對鍊錶進行拆分和排序。
class solution
public listnode sortlist(listnode head, listnode tail)
if (head.next == tail)
listnode slow = head, fast = head;
while (fast != tail)
} listnode list1 = sortlist(head, slow);
listnode list2 = sortlist(slow, tail);
listnode sorted = merge(list1, list2);
return sorted;
}public listnode merge(listnode head1, listnode head2) else
temp = temp.next;
}if (head1!= null) else if (head2!= null)
return dummyhead.next;
}}
複雜度分析
時間複雜度:o(nlogn),其中 n 是鍊錶的長度。
空間複雜度:o(logn),其中 n 是鍊錶的長度。空間複雜度主要取決於遞迴呼叫的棧空間。
使用自底向上的方法實現歸併排序,則可以達到 o(1) 的空間複雜度。
首先求得鍊錶的長度length,然後將鍊錶拆分成子鍊錶進行合併。
具體做法如下。
用 sublength 表示每次需要排序的子鍊錶的長度,初始時 sublength=1。
每次將鍊錶拆分成若干個長度為 sublength 的子鍊錶(最後乙個子鍊錶的長度可以小於sublength),按照每兩個子鍊錶一組進行合併,合併後即可得到若干個長度為 sublength×2 的有序子鍊錶(最後乙個子鍊錶的長度可以小於sublength×2)。合併兩個子鍊錶仍然使用「21. 合併兩個有序鍊錶」的做法。
將sublength 的值加倍,重複第 2 步,對更長的有序子鍊錶進行合併操作,直到有序子鍊錶的長度大於或等於 length,整個鍊錶排序完畢。
如何保證每次合併之後得到的子鍊錶都是有序的呢?可以通過數學歸納法證明。
初始時sublength=1,每個長度為 11 的子鍊錶都是有序的。
如果每個長度為 sublength 的子鍊錶已經有序,合併兩個長度為 sublength 的有序子鍊錶,得到長度為 sublength×2 的子鍊錶,一定也是有序的。
當最後乙個子鍊錶的長度小於sublength 時,該子鍊錶也是有序的,合併兩個有序子鍊錶之後得到的子鍊錶一定也是有序的。
class solution
int length = 0;
listnode node = head;
while (node != null)
listnode dummyhead = new listnode(0, head);
for (int sublength = 1; sublength < length; sublength <<= 1)
listnode head2 = curr.next;
curr.next = null;
curr = head2;
for (int i = 1; i < sublength && curr != null && curr.next != null; i++)
listnode next = null;
if (curr != null)
listnode merged = merge(head1, head2);
prev.next = merged;
while (prev.next != null)
curr = next;}}
return dummyhead.next;
}public listnode merge(listnode head1, listnode head2) else
temp = temp.next;
}if (head1!= null) else if (head2!= null)
return dummyhead.next;
}}
複雜度分析 鍊錶插入排序
void insertsort list sortascount,node node else p prior next q q next p int sortwithinsetmethod list sortasdata wchar pp p data if isnum pp int i 0 i ...
鍊錶插入排序
題目 用插入排序對鍊錶排序 樣例 given1 3 2 0 null,return0 1 2 3 null 思路 新建乙個以dummy開頭的鍊錶,並將dummy賦初值為0。令node dummy,通過移動新煉表中的node與要排序的鍊錶中的head,並比較node與head的值,來實現排序。如果he...
鍊錶插入排序
題目 用插入排序對鍊錶排序 思路 建立乙個新的鍊錶,將目標鍊錶依次插入先煉表中,小就插到前面,大就插到後面,如此一來,新的鍊錶就是目標鍊錶按大小次序排列的了。先看第一步,將目標鍊錶的第乙個元素插入所建立的空鍊錶,具體是先建立乙個地值存下頭節點的下乙個節點的位置,將頭節點的next變為空,連到一開始建...