Flatten Multilevel List II - Iterative O(n) Solution in Java


You are given a doubly linked list which in addition to the next and previous pointers, it could have a child pointer, which may or may not point to a separate doubly linked list. These child lists may have one or more children of their own, and so on, to produce a multilevel data structure, as shown in the example below.

Flatten the list so that all the nodes appear in a single-level, doubly linked list. You are given the head of the first level of the list.

 

Example 1:

Input: head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
Output: [1,2,3,7,8,11,12,9,10,4,5,6]
Explanation:

The multilevel linked list in the input is as follows:



After flattening the multilevel linked list it becomes:


Example 2:

Input: head = [1,2,null,3]
Output: [1,3,2]
Explanation:

The input multilevel linked list is as follows:

  1---2---NULL
  |
  3---NULL

Example 3:

Input: head = []
Output: []

 

How multilevel linked list is represented in test case:

We use the multilevel linked list from Example 1 above:

 1---2---3---4---5---6--NULL
         |
         7---8---9---10--NULL
             |
             11--12--NULL

The serialization of each level is as follows:

[1,2,3,4,5,6,null]
[7,8,9,10,null]
[11,12,null]

To serialize all levels together we will add nulls in each level to signify no node connects to the upper node of the previous level. The serialization becomes:

[1,2,3,4,5,6,null]
[null,null,7,8,9,10,null]
[null,11,12,null]

Merging the serialization of each level and removing trailing nulls we obtain:

[1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]

 


Note:

Your algorithm should be iterative (non-recursive) and run in O(n) time.


Problem Definition

Given a multilevel doubly linked list, flatten it into a single-level doubly linked list. The input is the head of the first level of the list, and the output should be the head of the flattened list.

Input:

head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]

Output:

[1,2,3,7,8,11,12,9,10,4,5,6]

Constraints:

Example:

Input: head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
Output: [1,2,3,7,8,11,12,9,10,4,5,6]

Understanding the Problem

The core challenge is to traverse a multilevel doubly linked list and flatten it into a single-level list. This involves handling the child pointers and ensuring that the order of nodes is preserved as per the depth-first traversal.

Common applications include flattening hierarchical data structures for easier processing or visualization.

Potential pitfalls include not correctly handling the child pointers or losing track of the next pointers during traversal.

Approach

To solve this problem, we can use an iterative approach with a stack to simulate the depth-first traversal. This avoids the potential pitfalls of recursion, such as stack overflow for deep lists.

Naive Solution

A naive solution might involve recursively traversing the list, but this is not optimal due to potential stack overflow issues and higher memory usage.

Optimized Solution

An optimized solution uses an iterative approach with a stack:

Algorithm

Here is a step-by-step breakdown of the algorithm:

  1. Initialize a stack and push the head of the list onto it.
  2. While the stack is not empty:
    • Pop a node from the stack.
    • If the node has a next node, push it onto the stack.
    • If the node has a child node, push it onto the stack and set the child pointer to null.
    • Update the next and previous pointers to flatten the list.

Code Implementation

// Definition for a Node.
class Node {
    public int val;
    public Node prev;
    public Node next;
    public Node child;
}

public class Solution {
    public Node flatten(Node head) {
        if (head == null) return head;

        // Create a stack to store nodes
        Stack<Node> stack = new Stack<>();
        stack.push(head);

        // Pointer to keep track of the previous node
        Node prev = null;

        while (!stack.isEmpty()) {
            Node curr = stack.pop();

            // If there was a previous node, link it with the current node
            if (prev != null) {
                prev.next = curr;
                curr.prev = prev;
            }

            // If there is a next node, push it onto the stack
            if (curr.next != null) {
                stack.push(curr.next);
            }

            // If there is a child node, push it onto the stack
            if (curr.child != null) {
                stack.push(curr.child);
                // Don't forget to remove the child pointer
                curr.child = null;
            }

            // Move the prev pointer to the current node
            prev = curr;
        }

        return head;
    }
}

Complexity Analysis

The time complexity of this approach is O(n), where n is the number of nodes in the list. This is because each node is processed exactly once.

The space complexity is O(n) in the worst case, due to the stack storing all nodes in the list.

Edge Cases

Consider the following edge cases:

Testing

To test the solution comprehensively, consider the following test cases:

Use a testing framework like JUnit to automate the testing process.

Thinking and Problem-Solving Tips

When approaching such problems, consider the following tips:

Conclusion

Flattening a multilevel doubly linked list is a common problem that tests your understanding of linked lists and iterative algorithms. By using a stack, we can efficiently flatten the list in O(n) time.

Understanding and solving such problems is crucial for improving your algorithmic thinking and coding skills.

Additional Resources

For further reading and practice, consider the following resources: