题目地址:
https://www.acwing.com/problem/content/description/1453/
给定一个单链表,请使用快速排序算法对其排序。要求:期望平均时间复杂度为 O ( n log n ) O(n\log n) O(nlogn),期望额外空间复杂度为 O ( log n ) O(\log n) O(logn)。思考题:如果只能改变链表结构,不能修改每个节点的val值该如何做呢?
数据范围:
链表中的所有数大小均在int范围内,链表长度在
[
0
,
10000
]
[0,10000]
[0,10000]。
可以用归并排序:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* quickSortList(ListNode* head) {
if (!head || !head->next) return head;
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode *slow = dummy, *fast = dummy;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
ListNode *l1 = dummy->next, *l2 = slow->next;
slow->next = nullptr;
l1 = quickSortList(l1), l2 = quickSortList(l2);
ListNode *prev = dummy;
while (l1 || l2) {
if (!l1) {
prev->next = l2;
break;
}
if (!l2) {
prev->next = l1;
break;
}
if (l1->val <= l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
return dummy->next;
}
};
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( log n ) O(\log n) O(logn)(递归栈深度)。
也可以用倍增法。每轮 2 k 2^k 2k个一组, k = 1 , 2 , . . . k=1,2,... k=1,2,...,并且对组内进行排序,在对长 2 k 2^k 2k的链表排序的时候,由于其前后 2 k − 1 2^{k-1} 2k−1长度的链表已经排序好,所以只需要中间断开,然后合并两个有序链表即可。当 2 k ≥ n 2^k\ge n 2k≥n的时候,则已经排好序了,退出。代码如下:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode *quickSortList(ListNode *head) {
ListNode *dummy = new ListNode(0);
dummy->next = head;
ListNode *prev = dummy;
for (int k = 1, sorted = 0; !sorted; k <<= 1, prev = dummy) {
sorted = true;
while (prev->next) {
// 从当前位置截取2k长度
ListNode *slow = prev, *fast = prev;
for (int i = 0; i < k && slow; i++) {
slow = slow->next;
if (fast && fast->next) fast = fast->next->next;
}
// 如果前一半已经少于k个了,则说明不用排了,退出循环
if (!slow) break;
ListNode *tail = nullptr;
if (fast) {
tail = fast->next;
fast->next = nullptr;
}
// 合并两个有序链表
ListNode *l1 = prev->next, *l2 = slow->next;
slow->next = nullptr;
while (l1 || l2) {
if (!l1) {
prev->next = l2;
break;
}
if (!l2) {
prev->next = l1;
break;
}
if (l1->val <= l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
while (prev->next) prev = prev->next;
// 和后面接上
prev->next = tail;
sorted = false;
}
}
return dummy->next;
}
};
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( 1 ) O(1) O(1)。