力扣原题:
先贴代码:
public class Solution143 {
public void reorderList(ListNode head) {
//找到原链表的中间节点
ListNode mid = middleNode(head);
//将原链表中点之后的链表反转逆置,再返回反转后的头节点
ListNode last = Reverse(mid);
//使中点的next域为空,断开链表
mid.next = null;
//将链表的前半部分和反转后的后半部分合并
merge(head,last);
}
public ListNode middleNode(ListNode head){
//寻找链表中点的方法为快慢指针法
ListNode slow = head;
ListNode fast = head;
//快指针每次走两步,慢指针每次走一步,等快指针到终点的时候慢指针正好在链表的中间位置
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
//返回慢指针所在的节点,即为中间节点
return slow;
}
public ListNode Reverse(ListNode mid){
//将中点之后的链表进行反转,使后一个节点指向前一个节点
ListNode cur = mid.next;
ListNode tmp = mid; //为了避免混淆,新建一个tmp节点替代mid进入循环
while (cur != null){
ListNode ret = cur.next;
cur.next = tmp;
tmp = cur;
cur = ret;
}
return tmp;
}
public void merge(ListNode l1 ,ListNode l2){
//最后进行合并操作,若原链表为奇数情况则l1和l2相遇时循环结束;
// 偶数情况则是l2的next域为null时循环结束
while (l1 != l2 && l2.next != null){
ListNode cur = l1.next;
ListNode tmp = l2.next;
l1.next = l2;
l2.next = cur;
l2 = tmp;
l1 = cur;
}
}
}
思路解析:
题目中要求我们将链表按照一定顺序重新排列,如下图演示,意思就是将倒数第一个排在第一个后面,倒数第二个排在第二个后面,依此类推。
由上图我们可以看到,原来链表的中间节点经重新排列后变成了最后一个节点,通过这点我们便可以从中间节点入手来解决问题。
因为单链表只能指向它的后继节点无法指向前驱节点,所以直接将最后一个节点排在第一个后面后,我们无法再对倒数第二个节点进行操作;必须先将原链表分为两个部分,把后半部分的链表再进行反转逆置操作,这样原来链表的最后一个节点就变成了后半部分链表的头节点,最后把前半部分链表和后半部分链表再来一个合并操作(按题目里的排列顺序合并),就可以解决问题了!