原題鏈接:https://leetcode-cn.com/problems/reorder-list/
1、map
void reorderList(ListNode* head) {
map<int,ListNode*> map;
ListNode *p=head;
int n=0;
while(p!=NULL){//使用map將鏈表順序存儲
map[n]=p;
p=p->next;
n++;
}
for(int i=0,j=n-1;i<j;i++,j--){//每次取i+j==1+n的節點鏈接即可
int pre=j-1;
map[pre]->next=map[j]->next;
map[j]->next=map[i]->next;
map[i]->next=map[j];
}
}
2、遞歸★★
void reorderList(ListNode* head) {
if(head==NULL||head->next==NULL||head->next->next==NULL){
return;
}
int len=0;
ListNode *p=head;
while(p!=NULL){//求出節點數
len++;
p=p->next;
}
reorderListHelper(head,len);
}
ListNode *reorderListHelper(ListNode *head,int len){
if(len==1){
ListNode *outTail=head->next;
head->next=NULL;
return outTail;
}
if(len==2){
ListNode *outTail=head->next->next;
head->next->next=NULL;
return outTail;
}
ListNode *tail=reorderListHelper(head->next,len-2);//相當於快慢指針,當len==1時,總數爲奇數,head正好走到中點;當len==2時,總數爲偶數,head走到中間左邊的節點。
ListNode *subHead=head->next;//子鏈表的頭結點
head->next=tail;
ListNode *outTail=tail->next;//上一層head對應的tail
tail->next=subHead;
return outTail;
}
3、雙鏈表
示例:
1 -> 2 -> 3 -> 4 -> 5 -> 6
第一步,將鏈表平均分成兩半
1 -> 2 -> 3
4 -> 5 -> 6
第二步,將第二個鏈表逆序
1 -> 2 -> 3
6 -> 5 -> 4
第三步,依次連接兩個鏈表
1 -> 6 -> 2 -> 5 -> 3 -> 4
代碼:
void reorderList(ListNode* head) {
if(head==NULL||head->next==NULL) return;
ListNode *p=head,*q=head;
while(q->next!=NULL&&q->next->next!=NULL){//找到中點,如果總長度是偶數,p,q長度相同;如果總長度是奇數,p比q長一個
p=p->next;
q=q->next->next;
}
q=reverse(p->next);//分隔鏈表,並且將後半部分倒序
p->next=NULL;
p=head;
while(q!=NULL){//再將兩個鏈表交錯合併
ListNode *tmp=q->next;
q->next=p->next;
p->next=q;
p=q->next;
q=tmp;
}
}
ListNode* reverse(ListNode* head){//遞歸倒序
if(head->next==NULL) return head;
ListNode* last=reverse(head->next);
head->next->next=head;
head->next=NULL;
return last;
}