Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes' values.
For example,
Given {1,2,3,4}
, reorder it to {1,4,2,3}
.
分析:
如果题目没有要求,可以用栈来存储链表后半段的结点,然后依次弹出往前插入链表,但是题目要求不能申请新空间来改变原来结点的值。
一开始我想到了一个时间是O(n),空间是O(1)的方法,就是首先找到中间结点,然后定位中间结点的前后两个结点,把next结点插入到prev结点之后,然后next向后指,prev结点向前指,刚要为我的想法高兴的时候,忽然发现,如果想让prev往前指,就必须得存储,或者每次遍历,所以这种思路是行不通的。
还是老老实实的先把后半段链表进行翻转,然后合并两个链表吧,这样的时间复杂度也是O(n),空间是O(1)
public class ReorderList {
public void reorderList(ListNode head) {
if(head == null)
return ;
ListNode node = head;
ListNode midPre = FindMidPre(node);
ListNode midNode = midPre.next;
//将链表从中间断开
midPre.next = null;
//反转后半段链表
ListNode ReverseListHeadNode = Reverse(midNode);
//合并两个链表
ListNode h1 = head;
ListNode h2 = ReverseListHeadNode;
MergeList(h1,h2);
}
public void MergeList(ListNode h1,ListNode h2){
ListNode curr = h1;
while(curr.next != null){
ListNode temp = curr.next;
curr.next = h2;
h2 = h2.next;
curr.next.next = temp;
curr = temp;
}
curr.next = h2;
}
public ListNode Reverse(ListNode head){
if(head == null || head.next == null)
return head;
ListNode prev = head;
ListNode curr = prev.next;
ListNode next = curr.next;
while(next != null){
curr.next = prev;
prev = curr;
curr = next;
next = next.next;
}
curr.next = prev;
head.next = null;
return curr;
}
public ListNode FindMidPre(ListNode head){
ListNode node = head;
ListNode slow = node,fast = node;
ListNode result = head;
while(fast != null && fast.next != null){
result = slow;
slow = slow.next;
fast = fast.next.next;
}
return result;
}
}