答案来自于评论里的解法,这里稍作分享,以及写下自己的理解和心得。
双端队列法:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
LinkedList<ListNode> queue = new LinkedList<>();
ListNode cur = head;
while (cur != null) {
queue.addLast(cur);
cur = cur.next;
}
while (!queue.isEmpty()) {
if (cur == null) {
cur = queue.pollFirst();
} else {
cur.next = queue.pollFirst();
cur = cur.next;
}
cur.next = queue.pollLast();
cur = cur.next;
}
if (cur != null) {
cur.next = null;
}
}
}
所谓双端队列法就是,用一个linkedList储存链表的节点,然后,输出一个开头,输出一个结尾。这种方法简单易懂,但是相对于下面的方法,复杂度略高,而且注意考虑链表可能形成环。
避免成环
if (cur != null) {
cur.next = null;
}
部分反转法:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
if (head == null) {
return;
}
ListNode l1 = head;
// 后半部分
ListNode l2 = AfterNode(head);
// 合并
ListNode l1_tmp, l2_tmp;
while (l1 != null && l2 != null) {
l1_tmp = l1.next;
l2_tmp = l2.next;
l1.next = l2;
l1 = l1_tmp;
l2.next = l1;
l2 = l2_tmp;
}
}
// 获取后半部分的链表
public ListNode AfterNode(ListNode head) {
// 快慢指针,寻找链表的中间位置
ListNode slow = head;
ListNode fast = head;
// 当快指针走完、慢指针正在到达中间的位置
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// slow为后半部分的链表
ListNode pre = null, cur = slow.next;
// 初始化l1变为前半部分
slow.next = null;
// 将其翻转
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
部分反转的思路也十分清晰,先利用快指针和慢指针求出链表中间的节点,然后对后面的节点反转,最后分别保存前后的链表,然后合并。