重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
大致思路是 :先找到中间节点,将前后链表分开,然后将后面的链表反转,最后将两个链表交叉插入。
创建虚拟节点:首先创建一个虚拟节点 vir,它的值设置为 -1(这个值不重要,因为虚拟节点不会被使用)。将 vir 的 next 指针指向链表的头节点 head,这样 vir 就成为了链表的新头节点。
使用快慢指针找到中点:初始化两个指针 slow 和 fast,都指向 vir。然后使用快慢指针法,fast 每次移动两个节点,slow 每次移动一个节点。当 fast 到达链表末尾时(即 fast == NULL 或 fast->next == NULL),slow 将指向链表的中间节点。
切断链表:将 slow->next 设置为 NULL,这样链表就被分成了两部分,slow 之前的部分是前半部分,slow->next(此时为 NULL)之后的部分是后半部分。
反转后半部分链表:初始化两个指针 pre 和 cur,pre 初始化为 NULL,cur 初始化为 slow->next(即后半部分的头节点)。然后使用一个循环来反转后半部分的链表。在循环中,cur->next 被设置为 pre,这样就将当前节点 cur 插入到 pre 和 NULL 之间,实现了反转。然后 pre 和 cur 都向前移动一个节点。
重新连接前后两部分链表:使用两个指针 fir 和 pre 分别指向前半部分和已反转的后半部分的头节点。然后使用一个循环来交替连接这两部分的节点,直到任一部分到达末尾。在循环中,fir->next 被设置为 pre,这样就将后半部分的节点连接到前半部分的末尾,然后 pre 和 fir 都向前移动一个节点。
结束循环:当 fir 或 pre 为 NULL 时,循环结束,此时链表已经被重新连接。
class Solution {
public:
void reorderList(ListNode* head) {
ListNode* vir=new ListNode (-1);
vir->next=head;
ListNode* slow=vir;
ListNode* fast=vir;
while(fast!=NULL && fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
ListNode* pre=NULL;
ListNode* cur=slow->next;
slow->next=NULL;
while(cur!=NULL)
{
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
ListNode* fir=head;
while(fir!=NULL && pre!=NULL)
{
ListNode* temp=fir->next;
ListNode* temp1=pre->next;
fir->next=pre;
pre->next=temp;
fir=temp;
pre=temp1;
}
}
};