Reorder List

https://oj.leetcode.com/problems/reorder-list/

Given a singly linked list LL0→L1→…→Ln-1→Ln,
reorder it to: L0→LnL1→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}.

解题思路:

这道题可以化解为三个子问题。第一,将一个链表分解为两半,也就是取出中间一个节点。第二,对后半链表进行倒置。第三,将前半链表和后半倒置后的链表归并。

第一个问题,前面已经处理过很多次了。可以首先next出整个链表的大小,然后在从头往后N/2个节点。也可以用快慢指针,快指针往后两个,慢指针才往后一个。这样,当快指针到达链表最后,慢指针指向的就是整个链表的中间。这里要注意的是,快指针走的方法,要判断两次。还有,这里取得的midNode实际上是前半链表的最后一个节点,而不是后半链表的第一个节点。

第二个问题,在 Reverse Nodes in k-Group 问题中也做过。

第三个问题,每次用两个引用保存下两个节点就可以。

对于链表的操作还是比较综合的,考虑好几个操作,不是太难,但是需要很细致。掌握的原则还是,链表的特点是可以往后取对象,不能往前。所以不能太快。

/**

 * Definition for singly-linked list.

 * class ListNode {

 *     int val;

 *     ListNode next;

 *     ListNode(int x) {

 *         val = x;

 *         next = null;

 *     }

 * }

 */

public class Solution {

    public void reorderList(ListNode head) {

        if(head == null || head.next == null){

            return;

        }

        

        //实际上后半段链表的头节点为midNode的下一个节点

        ListNode midNode = getMidNode(head);

        ListNode secondHead = midNode.next;

        midNode.next = null;

        secondHead = reverseList(secondHead);

        

        //firstList: head-midNode-null

        //secondList: secondHead-end-null

        mergeList(head, secondHead);

    }

    

    public ListNode getMidNode(ListNode head){

        if(head == null || head.next == null){

            return head;

        }

        ListNode fastNode = head;

        ListNode slowNode = head;

        while(fastNode.next != null){

            fastNode = fastNode.next;

            if(fastNode.next != null){

                fastNode = fastNode.next;

                slowNode = slowNode.next;

            }

        }

        return slowNode;

    }

    

    public ListNode reverseList(ListNode head){

        if(head == null || head.next == null){

            return head;

        }

        

        ListNode preNode = head;

        ListNode currentNode = head.next;

        ListNode nextNode = head.next.next;

        preNode.next = null;

        

        while(currentNode != null){

            currentNode.next = preNode;

            preNode = currentNode;

            currentNode = nextNode;

            //这个要特别注意,极可能nextNode已经null了

            if(nextNode != null){

                nextNode = nextNode.next;

            }

        }

        return preNode;

    }

    

    //两个链表归并,1-2,3-4归并为1-3-2-4

    public void mergeList(ListNode head, ListNode secondHead){

        while(head != null && secondHead != null){

            ListNode headNext = head.next;

            head.next = secondHead;

            ListNode secondHeadNext = secondHead.next;

            secondHead.next = headNext;

            head = headNext;

            secondHead = secondHeadNext;

        }

    }

}

上面的方法的时间复杂度为O(n)。之前还写了一个方法,思路是,每次都找到当前链表的最后一个节点,插入到前面的某个位置。例如,1-2-3-4-5-6,然后1-6-2-3-4-5,然后1-6-2-5-3-4。所以每个循环内,都要需要另外O(n)的时间去寻找尾节点,时间复杂度就为O(n^2)了,会time limit exceeded。还是提供下代码吧。

/**

 * Definition for singly-linked list.

 * class ListNode {

 *     int val;

 *     ListNode next;

 *     ListNode(int x) {

 *         val = x;

 *         next = null;

 *     }

 * }

 */

public class Solution {

    public void reorderList(ListNode head) {

        if(head == null || head.next == null || head.next.next == null){

            return;

        }

        ListNode start = head;

        ListNode end = head;

        

        while(start.next != null && start.next.next != null){

            while(end.next.next != null){

                end = end.next;

            }

            end.next.next = start.next;

            start.next = end.next;

            end.next = null;

            start = start.next.next;

            end = start;

        }

    }

}

update 2015/05/20:

二刷。这题包含寻找链表的中间节点、reverse list、merge list三个链表中比较重要的问题。可以说是leetcode里,链表题目中最为综合的一道,比较重要。一遍AC。

/**

 * 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;

        }

        ListNode preMid = getPreMidNode(head);

        // 中间节点是preMid.next

        ListNode head2 = reverse(preMid.next);

        preMid.next = null;

        // 将head和head2开头的两个listmerge

        while(head != null && head2 != null) {

            ListNode next = head2.next;

            head2.next = head.next;

            head.next = head2;

            head = head2.next;

            head2 = next;

        }

    }

    

    // 实际上取得的是中间节点的前一个节点,为了方便将其next置为null

    public ListNode getPreMidNode(ListNode head) {

        ListNode fast = head;

        ListNode slow = head;

        while(fast.next != null) {

            fast = fast.next;

            if(fast.next != null) {

                fast = fast.next;

                slow = slow.next;

            }

        }

        return slow;

    }

    

    // 将以head开头的list倒置

    public ListNode reverse(ListNode head) {

        if(head == null || head.next == null) {

            return head;

        }

        ListNode pre = head;

        ListNode cur = head.next;

        pre.next = null;

        while(cur != null) {

            ListNode next = cur.next;

            cur.next = pre;

            pre = cur;

            cur = next;

        }

        return pre;

    }

}

 

你可能感兴趣的:(order)