【LEETCODE OJ】Reorder List

Posted on 2014-04-04 07:35  卢泽尔  阅读(222)  评论(0)    收藏  举报

Problem link:

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

 

I think this problem should be a difficult problem, since it requries three classic algorithms on the single-linked list:

  1. Split a single-linked list into halves
  2. Reverse a single-linked list
  3. Combine two single-linked list into one alternately

Split a single-linked list into havles

The technique of Fast/Slow pointers is commonly used in the single-linked list problems.

Initially, let F and S both be the head of the list. Then each iteration, S goes one step and F goes two steps. The iteration is terminate when F touch the end of the list.

Then, S should be points to the first element of the second half of the list.

Reverse a sinigle-linked list

To reverse a single-linked list in O(n) time, we need scan the list from the second element. For each element, lets say E, we need insert it in the front of head and update the head as E. Because, the insertion may set E->next to the old head, we need an extra pointer to keep track the element after E. Do not forget to set the orginal first (the last after reversing) element's next to NULL (or set it at the begining).

Combine two single-linked list into one alternately

We need three pointers, one used to keep track the combined list, the other two pointers are used for keep the first uncombined element of two lists.


 

The C++ code is as follows.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode *head) {
        ListNode * h1 = head;
        ListNode * h2 = head;
        ListNode * p1 = NULL;
        ListNode * p2 = NULL;
        ListNode * p = head;
        
        // Special case: len=0, len=1, len=2
        for (int i=0; i<3; i++) {
            if (p == NULL) return;
            p = p->next;
        }

        // Step 1: split the list into halves
        while (h1 != NULL) {
            h2 = h2->next;
            h1 = h1->next;
            if (h1 != NULL) h1 = h1->next;
        }
        // now h2 is the head of the second half
        
        // Step 2: Reverse h2, h2 could not be NULL for len >= 2
        p2 = h2->next;
        // The head should be the last element after reversing
        h2->next = NULL;
        // Each time, we move the element of p2 in the front of head
        while(p2 != NULL) {
            p = p2->next;  // Record the next element
            p2->next = h2; // Insert p2 in fornt of h2
            h2 = p2;  // New head is p2
            p2 = p;  // Go on the next element
        }
        
        // Step 3: combine h1 and h2
        // The first element is always the first
        h1 = head->next;
        // each time we fill p->next with h1 or h2
        p = head;
        // Because we know that len(h1) = len(h2) or len(h1) = len(h2) + 1
        // so after picking one element from the first half,
        // the length of the second half should be not shorter than the first half
        // It is sufficient to terminate the combination when p2 is NULL
        while(h2 != NULL) {
            p->next = h2;
            h2 = h2->next;
            p = p->next;
            if (h1 != NULL) {
                p->next = h1;
                h1 = h1->next;
                p = p->next;
            }
        }
        p->next = NULL;
    }
};