方法一:数组
class Solution {
public:
void reorderList(ListNode* head) {
map<int, ListNode*> m;
int num = 0;
while (head) {
m[num] = head;
num++;
head = head->next;
}
num--;
if (num < 2) return;
int i = 0;
while (i < num) {
m[i]->next = m[num];
i++;
if (i == num) break; // 链表长度为偶数时会提前相遇
m[num]->next = m[i];
num--;
}
m[i]->next = nullptr;
}
};
方法二:递归
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next || !head->next->next ) return;
int len = 0;
ListNode* h = head;
// 求出节点数
while (h) {
len++;
h = h->next;
}
reorderListHelper(head, len);
}
private:
ListNode* reorderListHelper(ListNode* head, int len) {
if (len == 1) {
ListNode* outTail = head->next;
head->next = nullptr;
return outTail;
}
if (len == 2) {
ListNode* outTail = head->next->next;
head->next->next = nullptr;
return outTail;
}
// 得到对应的尾节点,并且将头结点和尾节点之间的链表通过递归处理
ListNode* tail = reorderListHelper(head->next, len - 2);
// 中间链表(已经处理好的中间部分,相当于最终链表的尾部)的头结点。(注:递归最先处理的是最终链表的尾部)
ListNode* subHead = head->next;
head->next = tail;
ListNode* outTail = tail->next; // 上一层 head 对应的 tail
tail->next = subHead;
return outTail;
}
};
方法三:重排链表
步骤一,用快慢指针找链表中点,把链表分为前后俩部分
步骤二,翻转后半部链表,翻转前要把前后两部分分开
步骤三,合并两部分链表
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next || !head->next->next) {
return;
}
//找中点,链表分成两个
ListNode* slow = head;
ListNode* fast = head->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
// 在反转之前需要的一个操作是将前后半部分断开
ListNode* newHead = slow->next;
slow->next = nullptr;
//第二个后面部分链表翻转
newHead = reverseList(newHead);
//链表节点依次连接
while (newHead) {
ListNode* temp = newHead->next;
newHead->next = head->next;
head->next = newHead;
head = newHead->next;
newHead = temp;
}
}
private:
ListNode* reverseList(ListNode* head) {
if (!head) return nullptr;
ListNode* tail = head;
head = head->next;
tail->next = nullptr;
while (head) {
ListNode* temp = head->next;
head->next = tail;
tail = head;
head = temp;
}
return tail;
}
};
class Solution {
public:
void reorderList(ListNode head) {
if (head == null || head.next == null) {
return;
}
// 步骤 1: 通过快慢指针找到链表中点
// 通过调节快慢指针的起始位置,可以保证前半部分的长度大于等于后半部分
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 步骤 2: 反转后半部分的链表
// 在反转之前需要的一个操作是将前后半部分断开
ListNode second = slow.next;
slow.next = null;
second = reverseList(second);
// 步骤 3: 合并前半部分链表以及反转后的后半部分链表
mergeList(head, second);
}
private ListNode reverseList(ListNode head) {
ListNode prev = null, tmp = null, pointer = head;
while (pointer != null) {
tmp = pointer.next;
pointer.next = prev;
prev = pointer;
pointer = tmp;
}
return prev;
}
private:
void mergeList(ListNode first, ListNode second) {
ListNode dummy = new ListNode(0);
ListNode pointer = dummy;
while (first != null && second != null) {
pointer.next = first;
first = first.next;
pointer.next.next = second;
second = second.next;
pointer = pointer.next.next;
}
// 因为我们之前找中点的时候保证了前半部分的长度不小于后半部分的长度
// 因此交叉后,多出来的部分只可能是前半部分,判断前半部分即可
if (first != null) {
pointer.next = first;
}
}