<LeetCode(Java版)>Reorder List

題目:

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

思路(1):喜歡效率較高的盆友直接看思路(2)
  此題要求在不改變節點value值的情況下,寫出完整代碼,給我的第一感覺就是又是亂七八糟的指針操作(對於指針操作,一般需要緩存當前訪問的節點,當前訪問節點的next節點等等)。看到這道題,給我的第一直覺就是如果能用棧去緩存,然後一邊出棧,一邊移動鏈表指針,這樣問題就解決了,於是第一版的思路出來了。

public void reorderList(ListNode head) {
        if(head == null)
            return;
        Stack<ListNode> stack = new Stack<ListNode>();
        ListNode node = head;
        int elementNum = 0;
        //將所有元素入棧
        while(node !=null){
            stack.push(node);
            node = node.next;
            elementNum++;
        }
        ListNode nowPos = head;
        ListNode nextPos = null;
        ListNode tailPos = null;
        for(int i = 0;i<elementNum/2;i++){
            if(tailPos != null)
                tailPos.next = nowPos;
            nextPos = nowPos.next;
            tailPos = stack.peek();
            nowPos.next = stack.pop();
            nowPos= nextPos;
        }

    }

  但這套代碼在LeetCode顯示Memory Limit Exceeded,也就是說,此種方法內存開銷會相當大,那麼有沒有另外的解決辦法呢?
思路(2):
  其實細心的盆友就可以看出來,將所有元素入棧是極大的浪費,因爲我們需要反轉的就是後半部分,但不是用Stack去緩存鏈表,而是直接操作鏈表反轉,這樣第二種思路就出現了。

        public void reorderList(ListNode head) {  
            if (head == null || head.next == null) return;  

            //把整個鏈表劃分成2個等長的子鏈表,如果原鏈表長度爲奇數,那麼第一個子鏈表的長度多1  
            ListNode slow = head, fast = head;  
            while (fast.next != null) {  
                fast = fast.next;  
                if (fast.next != null) fast = fast.next;  
                else break;  
                slow = slow.next;  
            }  

            ListNode head1 = head, head2 = slow.next;  
            slow.next = null;  

            //翻轉第二個子鏈表  
            ListNode cur = head2, post = cur.next;  
            cur.next = null;  
            while (post != null) {  
                ListNode tmp = post.next;  
                post.next = cur;  
                cur = post;  
                post = tmp;  
            }  
            head2 = cur;  

            //將兩個子鏈表合併  
            ListNode node1 = head1, node2 = head2;  
            while (node2 != null) {  
                ListNode tmp1 = node1.next;  
                ListNode tmp2 = node2.next;  
                node1.next = node2;  
                node2.next = tmp1;  
                node1 = tmp1;  
                node2 = tmp2;  
            }  
        } 

  LeetCode上顯示Runtime: 384 ms,Your runtime beats 97.45% of java coders.性能相當不錯了。其實這題還有其它的思路,有興趣的可以思索一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章