考察内容:链表,递归,二分
时间:2020-09-09 星期三
作者:guuzaa
掘金主页:🌏
题目描述 📃
题目链接 🔗,题目来自 leetcode。题目要求很简单,用 Nlog(N) 的时间复杂度和常数空间复杂度排序链表。
分析 💻
先实现一下数组的归并排序。
void mergeSort(vector<int> &nums, int left, int right) {
if (left < right) { // 递归出口
int mid = left + (right - left) >> 1;
mergeSort(nums, left, mid);
mergeSort(nums, mid+1, right);
merge(nums, left, mid, right);
}
}
void merge(vector<int> &nums, int left, int mid, int right) {
int h1 = left;
int h2 = mid + 1;
vector<int> tab;
while (h1 <= mid && h2 <= right) {
if (nums[h1] < nums[h2]) {
tab.emplace_back(nums[h1++]);
} else {
tab.emplace_back(nums[h2++]);
}
}
while (h1 <= mid) tab.emplace_back(nums[h1++]);
while (h2 < right) tab.emplace_back(nums[h2++]);
for (int i = 0; i < (int) tab.size(); i++) {
nums[left + i] = tab[i];
}
}
这道题目不过就是将数组换成了链表而已,大致思想没有变化。首先将链表不停分成两半,对左右链表递归调用归并排序,直到可以直接得到结果为止(链表长度为 1)。最后将左右有序链表归并为一个有序链表。
先实现链表的归并操作。
ListNode* merge(ListNode *head1, ListNode *head2) {
auto left = head1;
auto right = head2;
ListNode dummy(-1);
auto cur = &dummy;
while (left && right) {
if (left->val < right->val) {
cur->next = left;
left = left->next;
} else {
cur->next = right;
right = right->next;
}
cur = cur->next;
}
cur->next = head1 ? head1 : head2;
return dummy.next;
}
接着仿照数组的归并排序实现链表的。
ListNode* mergeSort(ListNode* head) {
// 递归出口
if (head == nullptr || head1->next == nullptr) return head;
// 将链表折半 就是找链表的中间节点(快慢指针)
ListNode *slow = head;
ListNode *fast = head->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
// 这时中间节点是slow 进行断链操作,将fast指向右侧链表。
fast = slow->next;
slow->next = nullptr;
// head 和 fast 是原链表折半后的左右链表
auto left = mergeSort(head);
auto right= mergeSort(fast);
return merge(left, right);
}
可以稍微简化一下代码,left 和 right 是没有必要定义的,直接写在 merge 即可,代码如下。
ListNode* mergeSort(ListNode* head) {
if (head == nullptr || head1->next == nullptr) return head;
ListNode *slow = head;
ListNode *fast = head->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
fast = slow->next;
slow->next = nullptr;
return merge(mergeSort(head), mergeSort(fast));
}
总结 📕:
- 如果这个题目考察的是用
Nlog(N)的时间复杂度和常数空间复杂度排序数组,我相信我是能做出来的。但是题目剑走偏锋,让我们排序链表。这就把我难住了。 - 归并链表操作、找链表中间节点代码有待加强。
- 研究生开学快乐 😄
全文完