问题描述
Sort a linked list in O(n log n) time using constant space complexity.
对一个链表进行排序,且时间复杂度要求为 O(n log n) ,空间复杂度为常量。问题分析&解题思路
要求时间复杂度为O(n log n),想到了归并排序。
利用归并的思想,递归地将当前链表分为两段,然后merge。
①找到链表中间节点(位置上的中间),从该节点处分成左右两部分;
②左右节点分别递归第①步;
③合并左右两个链表。代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *sortList(ListNode *head) {
if(NULL == head || NULL == head->next)
return head;
ListNode *mid = findMiddle(head);
ListNode *right = sortList(mid->next);
mid->next = NULL;
ListNode *left = sortList(head);
return mergeList(left, right);
}
//快慢指针找中间节点
ListNode *findMiddle(ListNode *head){
ListNode *fast = head->next;
//一定要是head->next,否则偶数个节点时,两段节点不均分
ListNode *slow = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
//合并两个链表
ListNode *mergeList(ListNode *left, ListNode *right){
if(NULL == left)
return right;
if(NULL == right)
return left;
ListNode *ret = new ListNode(0);
ListNode *head = ret;
//head指向两者较小的一个,记录其第一个节点
//两链表头继续向后走,head也向后走,且总是指向较小的
//直至其中一个为NULL,处理剩下的节点
//返回记录的头,ret->next
while(left != NULL && right != NULL)
{
if(left->val > right->val)
{
head->next = right;
right = right->next;
}
else
{
head->next = left;
left = left->next;
}
head = head->next;
}
if(NULL == left)
head->next = right;
if(NULL == right)
head->next = left;
return ret->next;
}
};
- 特别强调
代码中快指针必须声明为head->next。
此时,从慢指针处一分为二。head到slow是2个节点,slow->next到NULL也是2个节点。
如果声明快指针声明为head。
此时,head到slow是3个节点,slow->next是一个节点。
节点个数为奇数个时,必然一个比另一个多一个节点。