这道题目总的来说可以分三步,第一步是找到Linked List的中点,第二部是翻转Linked List的后半部分,第三部就是把Linked List按照题目的要求进行reorder,现在大的思路已经明确,接下来我们所需要的就是思考这三步怎样实现。
1->2->3->4->5->6
首先第一步的话,我们可以使用slow runner/fast runner来实现。对于第二步来说,假设题目中的Linked List如上面所示,第二步我们所要做的就是将上面的Linked List翻转成下面所示的:
1->2->3->6->5->4
这一步我们也是之前的一个题目,我们可以使用两个指针进行实现。
现在Linked List已经如上面的所示,我们可以使用三个指针:slow指向3,p1指向1,p2指向6;然后一步一步进行翻转,翻转的代码已经在下面给出,可以根据代码进行理解,关键问题是这个循环的终止条件是什么。通过对Linked List长度为奇数和偶数情况的分析,我们可以得到循环的终止条件为p1和p2中间有一个为空,或者有一个更为巧妙些的循环条件是slow == p1。整体的代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public void reorderList(ListNode head) {
if(head == null || head.next == null) return;
// Find the middle of the list
ListNode slow = head;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
// Reverse last half of linked list
slow.next = reverseList(slow.next);
// Reorder one by one
ListNode p1 = head;
ListNode p2 = slow.next;
while(p1 != null && p2 != null){
slow.next = p2.next;
p2.next = p1.next;
p1.next = p2;
p1 = p1.next.next;
p2 = slow.next;
}
}
private ListNode reverseList(ListNode head){
ListNode prev = null;
ListNode curr = head;
ListNode next = null;
while(curr != null){
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
思考:
1. 这道题目综合了一些非常基础的题目,所以对于基础类型的题目一定要掌握好,它们可能是解决更为复杂问题的阶梯
2. 这道题目使用了一种翻转的思想,就是对题目中的输入进行某种程度的翻转,从而达到更容易解决问题的目的;还有一种大翻转也同样经常使用,就是对整体进行reverse之后再对某些个体进行reverse,而不是谨小慎微地单单翻转某些个体,这种思想非常重要
3. 这道题目也是一个非常典型的Linked List题目,多多反复看看会有新的发现