题目描述:
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
递归:
1、递归的三要素
在我们了解了递归的基本思想及其数学模型之后,我们如何才能写出一个漂亮的递归程序呢?笔者认为主要是把握好如下三个方面:
1、明确递归终止条件;
2、给出递归终止时的处理办法;
3、提取重复的逻辑,缩小问题规模。
模型一: 在递去的过程中解决问题
function recursion(大规模){
if (end_condition){ // 明确的递归终止条件
end; // 简单情景
}else{ // 在将问题转换为子问题的每一步,解决该步中剩余部分的问题
solve; // 递去
recursion(小规模); // 递到最深处后,不断地归来
}
}
模型二: 在归来的过程中解决问题
function recursion(大规模){
if (end_condition){ // 明确的递归终止条件
end; // 简单情景
}else{ // 先将问题全部描述展开,再由尽头“返回”依次解决每步中剩余部分的问题
recursion(小规模); // 递去
solve; // 归来
}
}
2、合并链表:
在归来的过程中解决问题:
/*
功能:mergeList 合并两个有序链表
入参:struct ListNode* left,struct ListNode* right,两个有序链表头结点
返回值:合并后的链表头结点
*/
struct ListNode* mergeList(struct ListNode* left,struct ListNode* right){
if(left==NULL){// 明确的递归终止条件
return right;
}
if(right==NULL){// 明确的递归终止条件
return left;
}
//在将问题转换为子问题的每一步,解决该步中剩余部分的问题
if(left->val<right->val){
left->next=mergeList(left->next,right); //递到最深处后,不断地归来
return left;
}
else{
right->next=mergeList(left,right->next); //递到最深处后,不断地归来
return right;
}
}
递去的过程中解决问题:
/*
功能:merge 排序链表
入参:struct ListNode* node 链表头结点
返回值:合并后的链表头结点
*/
struct ListNode* merge(struct ListNode* node){
if(node==NULL || node->next==NULL){ //明确的终止条件
return node; //简单场景
}
// 先将问题全部描述展开,再由尽头“返回”依次解决每步中剩余部分的问题
struct ListNode* slow=node,*fast=node->next;
while(fast && fast->next){
slow=slow->next;
fast=fast->next->next;
}
struct ListNode* pre=slow->next;
slow->next=NULL;
struct ListNode* l=merge(node); // 递去 --缩小规模
struct ListNode* r=merge(pre); // 递去 --缩小规模
return mergeList(l,r); //归来中解决问题
}
struct ListNode* sortList(struct ListNode* head){
return head==NULL?head:merge(head);
}