https://leetcode.cn/problems/sort-list/submissions/499363940/?envType=study-plan-v2&envId=top-100-liked
这里我们直接进阶,用时间复杂度O(nlogn),空间复杂度O(1),来解决。
对于归并,如果自上而下的话,空间复杂度为O(n),因为需要开辟n个结点
所以我们要换种思路,自下而上,直接将链表看成独立的n个结点。
首先合并算法:
struct ListNode* merge(struct ListNode* head1,struct ListNode* head2)
{struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));dummyHead->val = 0,dummyHead->next = NULL;struct ListNode* tmp = dummyHead,*h1=head1,*h2=head2;while(h1 && h2){if(h1->val <= h2->val){tmp->next = h1;h1=h1->next;}else{tmp->next = h2;h2 = h2->next;}tmp = tmp->next;}if(h1){tmp->next = h1;}if(h2){tmp->next = h2;}return dummyHead->next;
}
思路:
这里的细节在于:找每组的子区间,找子区间的判断条件,隔离子区间,链接每一组,找下一组的子区间。
具体代码如下:
struct ListNode* merge(struct ListNode* head1,struct ListNode* head2)
{struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));dummyHead->val = 0,dummyHead->next = NULL;struct ListNode* tmp = dummyHead,*h1=head1,*h2=head2;while(h1 && h2){if(h1->val <= h2->val){tmp->next = h1;h1=h1->next;}else{tmp->next = h2;h2 = h2->next;}tmp = tmp->next;}if(h1){tmp->next = h1;}if(h2){tmp->next = h2;}return dummyHead->next;
}struct ListNode* sortList(struct ListNode* head) {if(head == NULL)return head;int len = 0;//长度for(struct ListNode* cur = head;cur!=NULL;cur=cur->next)len++;struct ListNode* dummy = malloc(sizeof(struct ListNode));dummy->val = 0,dummy->next = head;//自底向上归并排序for(int sublen = 1;sublen < len;sublen*=2){struct ListNode* pre = dummy,*cur=dummy->next;//每次从新的头开始记录while(cur){struct ListNode* head1 = cur;//第一个头就是curfor(int i = 1;i<sublen && cur->next!=NULL;i++)//找1子区间的尾,并且2子区间不为空{cur = cur->next;}//如果for是在cur->next == NULL结束的,那2子区间头就是空struct ListNode* head2=cur->next;//2子区间的头cur->next = NULL;//将1子区间分离出来cur = head2;//再找2子区间的尾for(int i = 1;i<sublen && cur!=NULL;i++){cur=cur->next;}struct ListNode* next = NULL;//记录下一组的头//如果cur为空,说明已经到了整个链表的最后if(cur != NULL)//cur不为空{next = cur->next;//记录下一组的头,可空可不空cur->next = NULL;//分离2子区间}struct ListNode* Merged = merge(head1,head2);//记录每次合并后的头pre->next = Merged;while(pre->next)//走到合并后的1,2区间的尾,pre来链接每一组{pre = pre->next;}cur = next;//进入下一组}}return dummy->next;
}