AcWing 1451 單鏈錶快速排序
題目
給定一個單鏈表,請使用快速排序算法對其排序
要求:期望平均時間複雜度爲O(nlogn)
,期望額外空間複雜度爲O(logn)
思考題: 如果只能改變鏈表結構,不能修改每個節點的val
值該如何做呢
數據範圍
鏈表中的所有數大小均在int
範圍內,鏈表長度在[0, 10000]
輸入樣例:
[5, 3, 2]
輸出樣例:
[2, 3, 5]
思路
首先我們要思考快排的思想
快排就是選定一個目標值,將比目標值小的都放在左邊,比目標值大的都放在右邊,然後遞歸處理左邊和右邊,最後將三者(還有等於目標值的可能)合併,那在鏈表中如何實現快排呢
很簡單,我們要定義三個鏈表,分別代表left、mid、right
,我們設定一個目標值,假設爲int val = head->val
,通過遍歷原鏈表,我們將比val
小的放在left
後,將比val
大的放在right
後,相等的放在mid
後,然後遞歸處理left
和right
,最後將三者連接即可
這裏需要注意幾個細節,因爲三個鏈表的表頭指針我們後面會用到,所以我們需要一個變量來記錄每個鏈表尾節點的指針:ltail、mtail、rtail
,通過這三個指針,我們可以實現向鏈表尾插入數據;在遍歷鏈表結束後,要將三個尾指針指空,否則系統無法判斷鏈表是否結束了,下面是代碼
代碼
class Solution {
public:
ListNode* quickSortList(ListNode* head) {
if (!head || !head->next) return head;
auto left = new ListNode(-1), mid = new ListNode(-1), right = new ListNode(-1);
auto ltail = left, mtail = mid, rtail = right;
int val = head->val;
for (auto p = head; p; p = p->next) {
if (p->val < val) ltail = ltail->next = p;
else if (p->val == val) mtail = mtail->next = p;
else rtail = rtail->next = p;
}
ltail->next = rtail->next = mtail->next = NULL;
left->next = quickSortList(left->next);
right->next = quickSortList(right->next);
auto lh = left;
while (lh->next) lh = lh->next;
lh->next = mid->next;
while (lh->next) lh = lh->next;
lh->next = right->next;
return left->next;
}
};