题目大意:给一个单链表:L0->L1->L2->L3-> ... ->Ln-1->Ln,将其重排为:L0->Ln->L1->Ln-1->L2->Ln-2->...
要求:1、就地重排;2、改变指针的指向,而不是直接修改结点的值。
分析:直接的想法就是依次截取最后的结点,插入到要求的位置。但是,考察每个插入的位置需要遍历一遍单链表,每次找到最后一个结点也需要遍历一遍单链表,程序结构为两个嵌套的循环,时间复杂度是O(n*n)的。提交后超时。
改进的算法如下:
先遍历一遍链表,统计链表长度,根据长度,截取链表的后半段;然后将后半段倒置(头插法);再将前半段和后半段两个单链表交替合并。算法的时间复杂度应该是O(n),AC。算法图解如下:
代码如下:
#include<iostream>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
void reorderList(ListNode *head) {
ListNode *p,*q,*r,*h1,*h2;
int len=0,len1,len2;
if(!head || !head->next || !head->next->next)
return ;
p=head;
while(p){//获取整个链表长度
++len;
p=p->next;
}
if(len%2==0){
len1=len/2+1;
len2=len/2-1;
}else{
len1=len/2+1;
len2=len/2;
}
q=head;
h2=head->next;
for(int i=1;i<len1;++i){
q=q->next;
h2=h2->next;
}
q->next=NULL;//截断原始链表
p=h2;//头插法,将后半段链表倒置
q=p->next;
while(q){
p->next=q->next;
q->next=h2;
h2=q;
q=p->next;
}
//交替合并两段链表
h1=head;
p=h1->next;
q=h2->next;
while(q){
h1->next=h2;
h2->next=p;
h1=p;
h2=q;
p=h1->next;
q=h2->next;
}
h1->next=h2;
h2->next=p;
}
};