码迷,mamicode.com
首页 > 其他好文 > 详细

Reorder List

时间:2015-03-04 16:22:21      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:

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

 

Reorder List

标签:

原文地址:http://www.cnblogs.com/NickyYe/p/4313380.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!