题目描述
给定一个单链表 L : L 0 → L 1 → … → L n − 1 → L n L:L_0→L_1→…→L_{n-1}→L_n L:L0→L1→…→Ln−1→Ln,将其重新排列后变为: L 0 → L n → L 1 → L n − 1 → L 2 → L n − 2 → … L_0→L_n→L_1→L_{n-1}→L_2→L_{n-2}→… L0→Ln→L1→Ln−1→L2→Ln−2→…。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
解题思路
把链表分成两半,然后把后面的一半翻转,然后再把两半链表拼接在一起即可。
参考代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
if(!head)
return;
ListNode* dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode* pSlow = head;
ListNode* pQuick = head;
ListNode* pLastNodeInFront = nullptr; // 记录前一部分链表的最后一个节点
while(pQuick && pQuick->next){ // 此时pSlow指向链表中心(快慢指针法)
pLastNodeInFront = pSlow;
pSlow = pSlow->next;
pQuick = pQuick->next->next;
}
if(pQuick){ // 链表元素个数为奇数时
pLastNodeInFront = pSlow;
pSlow = pSlow->next;
}
if(!pSlow) // 当链表只有一个节点时,这里要特判,否则可能报空指针异常
return;
// 翻转后一部分链表
ListNode* pPre = nullptr;
ListNode* pNode = pSlow;
while(pNode){
ListNode* pNext = pNode->next;
pNode->next = pPre;
pPre = pNode;
pNode = pNext;
}
pLastNodeInFront->next = nullptr; // 断开前后两部分(重要!)
// 重排链表
ListNode* p1 = head;
ListNode* p2 = pPre;
pNode = dummyHead;
while(p1 || p2){
ListNode *p1_next = nullptr, *p2_next = nullptr;
if(p1)
p1_next = p1->next;
if(p2)
p2_next = p2->next;
pNode->next = p1;
pNode = pNode->next;
pNode->next = p2;
pNode = pNode->next;
p1 = p1_next;
p2 = p2_next;
}
}
};