[链表]–重排链表
题目链接
题目
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
解析
首先确定一下眼神:这意思是将后半部分链表从后向前依次插入到该节点关于中心对称的节点的next,好了是双指针法。
- 首先需要从后向前地将某个节点插入,作为一个单链表是没有 prev 指针域的,所以需要反转后半部分链表:定义快慢指针寻找中间节点,然后反转后半部分链表。
- 在反转后半部分链表后,插入节点或者说合并两个链表就好:
(1)首先令两个指针分别从两个新链表的头节点出发,需要做的是将后面链表的节点插入到前面链表的对应位置后面;
(2)插入之后会发现两个节点的 next 指针域都发生了变化。所以需要将两个指针原有的 next 保存起来作为标志用于下次插入;
(3)插入节点了:把你的 next 给我,那我就做你的 next ,顺序当然不能改变否则必将大乱;
(4)插入之后就找不到自己的组织了,所以需要做的就是将刚才保存的标志给我看看,然后继续遍历插入;
(5)直到两个指针相遇了,就说明遍历完了。需要注意的是,偶数个数的链表指针不会相遇,两个指针最后一次是相邻的,所以判断一下就 ok。
(6)最后别忘了每个链表尾节点的 next 是 null。
代码实现
public class Solution143 {
/**
* Definition for singly-linked list
*/
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
/**
* 1.快慢指针寻找中间节点
* 2.反转后半部分链表
* 3.合并两个链表
*/
public void reorderList(ListNode head) {
if (head == null) return;
// 快慢指针寻找中间节点
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
// 反转后半部分链表
ListNode prev = slow;
slow = slow.next;
while (slow != null) {
ListNode slowNext = slow.next;
slow.next = prev;
prev = slow;
slow = slowNext;
}
// 合并两个链表
fast = head;
slow = prev;
while (fast != slow) {
ListNode slowNext = slow.next;
ListNode fastNext = fast.next;
slow.next = fast.next;
fast.next = slow;
slow = slowNext;
fast = fastNext;
// 节点个数为偶数
if (fast.next == slow) {
break;
}
}
slow.next = null;
}
}
-----------------------------------------------------------------------------有始有终分割线----------------------------------------------------------------------------------