Sort a linked list in O(n log n) time using constant space complexity.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
Solution: This is a standard mergesort , but only in linklist way. Merge Sort is O(nlgn) and the sort needs to be done in place so it is O(1) space
Be careful:
1) when we divide the link lists to two parts, do not forget to point the last left next to nullptr;
2) in merge, for efficiecy, always move the pointer as far as possible, denote local start and end, insert the whole local piece to the other; Then continue with next comparison.
3)The merge code is too long. Need look for a shorter code and easier logic.
:::Just wrote a recursive version. It is easier logic, but if there are many continuous elements, it wasted some link broken and re-connect.
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (!l1) return l2;
if (!l2) return l1;
//l1 and l2 have nodes
ListNode*ret ;
if (l1->val<l2->val){
ret=l1;
ListNode*l1next= mergeTwoLists(l1->next, l2);
l1->next=l1next;
}else{
ret=l2;
ListNode*l2next= mergeTwoLists(l1, l2->next);
l2->next=l2next;
}
return ret;
}
////////////////////__________________________________________________________
//change with more moving forward
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (!l1) return l2; if (!l2) return l1;
//l1 and l2 have nodes
ListNode*ret ;
if (l1->val<l2->val){
ret=l1;
while (l1->next && l1->next->val<l2->val){
l1=l1->next;
}
ListNode*l1next= mergeTwoLists(l1->next, l2);
l1->next=l1next;
}else{
ret=l2;
while (l2->next && l2->next->val<=l1->val){
l2=l2->next;
}
ListNode*l2next= mergeTwoLists(l1, l2->next);
l2->next=l2next;
}
return ret;
}
///////////////////__________________________________________________________ class LnikListSort{
public:
ListNode* sortL(ListNode* head, int N){
//end condition
if (N<2) return head;
if (head==nullptr) return head;
if (N==2){
if (head->val<head->next->val) return head;
ListNode* next= head->next;
head->next->next= head;
head->next=nullptr;
return next;
}
//get the middle Node
ListNode* mid=head;
for (int i=0; i<N/2; ++i){
mid= mid->next;
}
ListNode* midNext=mid->next;
mid->next=nullptr;
int left= N/2+1; //count mid in left
int right=N-N/2-1;
ListNode* headL=sortL(head, left);
ListNode* headR=sortL(midNext, right);
return mergeL(headL, left, headR, right);
}
ListNode* mergeL(ListNode* headL, int left, ListNode* headR, int right){
if (left==0) return headR;
if (right==0) return headL;
ListNode *curL=headL, *curR=headR, *ret;
if (headL->val<headR->val) ret=headL;
else ret= headR;
int l=0, r=0;
//2 3 //4
while (l<left && r<right ){
if (curL->val< curR->val) {
while(l+1<left && curL->next->val<=curR->val){
curL=curL->next;
l++;
}
if (l+1<left ){ //l has next
ListNode* frontR=curR;
while (r+1<right && curL->next->val>= frontR->next->val){
frontR=frontR->next;
r++;
}
ListNode* rHeadNew=frontR->next; r++;
{ //insert in curR~frontR cur right node, l++
ListNode* lNext= curL->next;
curL->next=curR;
frontR->next=lNext;
curL=lNext; //l=l;
l++;
curR=rHeadNew;
}
}else{ //l is done; we link current r, done
curL->next=curR;
break;
}
}else{
while(r+1<right && curR->next->val<=curL->val){
curR=curR->next;
r++;
}
if (r+1<right ){ //r has next
ListNode* frontL=curL;
while (l+1<left && curR->next->val>= frontL->next->val){
frontL=frontL->next;
l++;
}
ListNode* lHeadNew=frontL->next; l++;
{ //insert in curR~frontR cur right node, l++
ListNode* rNext= curR->next;
curR->next=curL;
frontL->next=rNext;
curR=rNext; //l=l;
r++;
curL=lHeadNew;
}
}else{ //l is done; we link current r, done
curR->next=curL;
break;
}
}
}
return ret;
}
ListNode* sortList(ListNode* head) {
//count the length of the list
ListNode* cur=head;
int N=0;
while (cur){
N++;
cur=cur->next;
}
return sortL(head, N);
}
};
No comments:
Post a Comment