------------------------------本题链接---------------------------
题目描述
将给定的单链表 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→…
要求: 使用原地算法,不能改变节点内部的值,需要对实际的节点进行交换。
示例
输入
单链表:{10,20,30,40}
返回值
重新排序链表:{10,40,20,30}
思路
由于要将后半部分的节点插入前半部分,我们不妨将该链表一分为二,将后半部分链表倒序,然后再一个一个插入前半部分链表
算法过程
- 采用快慢指针找到中间节点
- 翻转后半部分链表
- 将倒序的后半部分链表插入前半部分链表中
解答
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public void reorderList(ListNode head) {
if(head == null || head.next == null || head.next.next==null) return;
ListNode fast = head, slow = head;
// 1.快慢指针,寻找中间节点
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
// 2.翻转后半部分链表
ListNode after = slow.next;
slow.next = null;
ListNode pre = null, tmp;
while(after != null){
// 暂存下一节点
tmp = after.next;
// 当前节点指向它原来的下一节点
after.next = pre;
// 保存当前节点,使其之后的点可以指向它
pre = after;
// 指针获取暂存信息,指向下一节点
after = tmp;
}
// 3.合并链表
ListNode first = head; // 前半部分
after = pre; // 翻转的后半部分
while(first != null && after != null){
ListNode before_tmp = first.next;
ListNode after_tmp = after.next;
first.next = after;
after.next = before_tmp;
first = before_tmp;
after = after_tmp;
}
}
}