<p align="center"> <a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a> <a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a> <a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a> <a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a> </p> <p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> # 143.重排链表  # 思路 本篇将给出三种C++实现的方法 * 数组模拟 * 双向队列模拟 * 直接分割链表 ## 方法一 把链表放进数组中,然后通过双指针法,一前一后,来遍历数组,构造链表。 代码如下: ```C++ class Solution { public: void reorderList(ListNode* head) { vector<ListNode*> vec; ListNode* cur = head; if (cur == nullptr) return; while(cur != nullptr) { vec.push_back(cur); cur = cur->next; } cur = head; int i = 1; int j = vec.size() - 1; // i j为之前前后的双指针 int count = 0; // 计数,偶数去后面,奇数取前面 while (i <= j) { if (count % 2 == 0) { cur->next = vec[j]; j--; } else { cur->next = vec[i]; i++; } cur = cur->next; count++; } if (vec.size() % 2 == 0) { // 如果是偶数,还要多处理中间的一个 cur->next = vec[i]; cur = cur->next; } cur->next = nullptr; // 注意结尾 } }; ``` ## 方法二 把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表。这种方法比操作数组容易一些,不用双指针模拟一前一后了 ```C++ class Solution { public: void reorderList(ListNode* head) { deque<ListNode*> que; ListNode* cur = head; if (cur == nullptr) return; while(cur->next != nullptr) { que.push_back(cur->next); cur = cur->next; } cur = head; int count = 0; // 计数,偶数去后面,奇数取前面 ListNode* node; while(que.size()) { if (count % 2 == 0) { node = que.back(); que.pop_back(); } else { node = que.front(); que.pop_front(); } count++; cur->next = node; cur = cur->next; } cur->next = nullptr; // 注意结尾 } }; ``` ## 方法三 将链表分割成两个链表,然后把第二个链表反转,之后在通过两个链表拼接成新的链表。 如图: <img src='https://code-thinking.cdn.bcebos.com/pics/143.重排链表.png' width=600> </img></div> 这种方法,比较难,平均切割链表,看上去很简单,真正代码写的时候有很多细节,同时两个链表最后拼装整一个新的链表也有一些细节需要注意! 代码如下: ```C++ class Solution { private: // 反转链表 ListNode* reverseList(ListNode* head) { ListNode* temp; // 保存cur的下一个节点 ListNode* cur = head; ListNode* pre = NULL; while(cur) { temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next cur->next = pre; // 翻转操作 // 更新pre 和 cur指针 pre = cur; cur = temp; } return pre; } public: void reorderList(ListNode* head) { if (head == nullptr) return; // 使用快慢指针法,将链表分成长度均等的两个链表head1和head2 // 如果总链表长度为奇数,则head1相对head2多一个节点 ListNode* fast = head; ListNode* slow = head; while (fast && fast->next && fast->next->next) { fast = fast->next->next; slow = slow->next; } ListNode* head1 = head; ListNode* head2; head2 = slow->next; slow->next = nullptr; // 对head2进行翻转 head2 = reverseList(head2); // 将head1和head2交替生成新的链表head ListNode* cur1 = head1; ListNode* cur2 = head2; ListNode* cur = head; cur1 = cur1->next; int count = 0; // 偶数取head2的元素,奇数取head1的元素 while (cur1 && cur2) { if (count % 2 == 0) { cur->next = cur2; cur2 = cur2->next; } else { cur->next = cur1; cur1 = cur1->next; } count++; cur = cur->next; } if (cur2 != nullptr) { // 处理结尾 cur->next = cur2; } if (cur1 != nullptr) { cur->next = cur1; } } }; ``` # 其他语言版本 Java: Python: Go: JavaScript: ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>