給定一個單鏈表 L:L0→L1→…→Ln-1→Ln ,
將其重新排列後變爲: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。
示例 1:
給定鏈表 1->2->3->4, 重新排列爲 1->4->2->3.
示例 2:
給定鏈表 1->2->3->4->5, 重新排列爲 1->5->2->4->3.
這個題其實就是將後面的鏈表的節點依次進行往前面的空裏進行插入。其實就是插空法。
分三步:
1、找到鏈表的中點
2、反轉鏈表 因爲鏈表的特性 我們只能從後往前依次插入 這樣需要從鏈表的最後開始
這裏需要注意的一點 我們對鏈表的反轉其實只需要從中間結點的下一個開始就行,因爲中間結點最後都會掛在重排後的最後一個 我們就不需要對齊進行反轉。
3、一次進行往前的結點插入。
public void reorderList(ListNode head) {
if (null == head || null == head.next) {
return;
}
//1、找鏈表中點
ListNode mid = findMid(head);
/*2、反轉後半部分鏈表
後半部分的開始反轉的點 這個地方其實是要注意的 我們是從找到的中點
的下一個結點開始反轉 因爲不管鏈表是奇數個結點還是偶數個結點 中間結點是不需要進行往前插入的
所以我們只需要把需要進行插入的反轉 並且將mid與後面的斷開 這個實際就將鏈表分爲兩部分了
*/
ListNode reverseNeed = mid.next;
mid.next = null;
ListNode needInsert = reverseList(reverseNeed);
//3、往前依次插入
ListNode leftInserted = head;
ListNode leftInsertedNext = null;
ListNode needInsertNext = null;
while(null != needInsert){
//先將要插入的結點 和左邊插入的結點的下一個都保存起來
leftInsertedNext = leftInserted.next;
needInsertNext = needInsert.next;
//插入結點 改變結點的指向
leftInserted.next = needInsert;
needInsert.next = leftInsertedNext;
//分別往前走一步 繼續循環
leftInserted = leftInsertedNext;
needInsert = needInsertNext;
}
}
private ListNode findMid(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(null != fast && null != fast.next){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
//反轉鏈表
private ListNode reverseList(ListNode head){
ListNode cur = head;
ListNode pre = null;
ListNode next = null;
while(null != cur){
//1 保存下一個結點
next = cur.next;
//2 反轉結點 改變指向
cur.next = pre;
//繼續下一個結點
pre = cur;
cur = next;
}
return pre;
}