给定一个单链表L: L 0→ L 1→...→ L n-1→ L n,
重新排列后为:L 0→ L n→ L 1→ L n-1→ L 2→ L n-2→......
必须在不改变节点值的情况下进行原地操作。
样例
给出链表 1->2->3->4->null
,重新排列后为1->4->2->3->null
。
挑战
你可以在 不改变节点值的情况下就地执行此操作 吗?
解题思路:
先使用快慢指针,找到中间元素,然后将其对半分为前后两个链表。然后将后半部分链表翻转,最后链接前后链表即可。
注意快慢指针找中间元素,最后只与慢指针有关。快速后被重新定义为后链表头。
翻译后链表的操作步骤与Lintcode 35:Reverse Linked List相同。
/**
* Definition for ListNode
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
/**
* @param head: The head of linked list.
* @return: nothing
*/
public void reorderList(ListNode head) {
// write your code here
if(head == null || head.next == null)
return;
//利用快慢指针返回中间节点
ListNode mid = findMid(head);
//后半部分链表反转后的头部为head2
ListNode head2 = reverse(mid.next);
//前半部分末尾添上null
mid.next = null;
//连接前后两部分链表
merge(head, head2);
}
private ListNode findMid(ListNode head){
ListNode slow = head;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode reverse(ListNode head){
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
private void merge(ListNode head1, ListNode head2){
while(head1 != null && head2 != null){
ListNode head2Next = head2.next;
head2.next = head1.next;
head1.next = head2;
head1 = head1.next.next;
head2 = head2Next;
}
}
}