目录
题目:
示例:
分析:
代码:
题目:
示例:
分析:
给我们一个链表,让我们按照题目要求原地修改重排链表。
那么具体怎么个重排法呢,题目给出了一串式子,其实就是把链表分为前后两段,然后在前半段的节点中间穿插反过来的后半段链表,可以结合着我下面的动图理解理解。
我们现在就知道应该要怎么重排了,那么我们应该怎么做才能达到这样的效果呢?
我们可以发现一个规律,就是最前面的节点要指向最后面的节点,第二前的节点要指向第二后的节点,这个规律让我一下子就想到了双指针,然而直接对链表指向双指针的话,左指针可以右移,但是右指针不能左移,因为节点只有next(后驱指针),没有pre(前驱指针),所以我们得想个办法。
那就是用一个容器先按顺序把链表的每个节点都先缓存起来,再使用双指针的做法。
并且我们可以发现,按照这样的重排法,重排之后的链表末尾节点变成了重排之前链表的中间节点,因此我们可以先把中间节点的next改为空指针,也就是让中间的节点变为末尾节点。
一切准备就绪之后就可以使用双指针了,我们将左指针指向的节点的next指向右指针指向的节点,然后右指针指向的节点再指回左指针+1的指向的节点。然后再同时移动左右指针,直到左指针+1>=右指针,为什么要+1呢。
这就涉及到我们刚才的预处理了,我们提前把中间节点给设为链表末尾了,也就是它的next指向的是空指针,所以我们不需要处理,也不能处理它,要跳过它,所以要+1。
并且这个预处理是我们必须做的,我们可以先假设我们没有预处理中间节点,那么按照我们刚才的循环过程,最终会导致中间节点的next是自己本身,因此我们不得不提前将中间节点的指向改为空指针,并且在双指针循环的时候跳过这个节点。
代码:
class Solution {
public:
void reorderList(ListNode* head) {
vector<ListNode*>cache; //缓存住所有节点
while(head){
cache.push_back(head);
head=head->next;
}
int l=0,r=cache.size()-1;
//将链表的中间节点的next改为空指针,因为重排之后链表的最中间会变成链表的末尾
if(cache.size()%2==0) cache[(l+r)/2+1]->next=nullptr;
else cache[(l+r)/2]->next=nullptr;
//修改左右指针所指节点的指向
while(l+1<r){
cache[l]->next=cache[r];
cache[r]->next=cache[l+1];
l++,r--;
}
}
};