Talentd
FleetCode
Make and follow sheets.Sign in

Flatten a Multilevel Doubly Linked List solution and explanation

MediumDepth-First SearchDoubly-Linked ListLinked List5 min read63.3% acceptanceUpdated 9 Apr 2026
Flatten a Doubly Linked List | Leetcode 430 | DSA Series by @shradhaKDShradha Khapra · 24:47 · 65K viewsWatch on YouTube
9 more videos on this problem
  1. Flatten a Doubly Linked List | Leetcode 430 | DSA Series by @shradhaKDShradha Khapra · 24:47 · 65K views
  2. Flatten a Multilevel Doubly Linked List | LeetCode 430 | C++, Java, PythonKnowledge Center · 25:00 · 18K views
  3. Leetcode - Flatten a Multilevel Doubly Linked List (Python)Timothy H Chang · 8:13 · 6K views
  4. [Java] Leetcode 430. Flatten a Multilevel Doubly Linked List [LinkedList #4]Eric Programming · 7:29 · 6K views
  5. LeetCode 430. Flatten a Multilevel Doubly Linked Listhappygirlzt · 5:17 · 4K views
  6. Flatten a Multilevel Doubly Linked List | Leet code 430 | Theory explained + Python code | July codeSai Anish Malla · 7:12 · 4K views
  7. Flatten a Multilevel Doubly Linked List | Leetcode 430 | Live coding session 🔥🔥🔥Coding Decoded · 9:11 · 2K views
  8. Flatten a Multilevel Doubly Linked List | Day 10 | [ July LeetCoding Challenge ] [ Leetcode #430]Algorithms Made Easy · 5:59 · 2K views
  9. Leetcode - Flatten a Multilevel Doubly Linked ListCode with Kavit · 13:25 · 424 views
  10. LEETCODE : Flatten a Multilevel Doubly Linked List [ USING STACKS ]Anand Pandey · 9:20 · 421 views

The problem

You are given a doubly linked list, which contains nodes that have a next pointer, a previous pointer, and an additional child pointer. This child pointer may or may not point to a separate doubly linked list, also containing these special nodes. 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.

Given the head of the first level of the list, flatten the list so that all the nodes appear in a single-level, doubly linked list. Let curr be a node with a child list. The nodes in the child list should appear after curr and before curr.next in the flattened list.

Return the head of the flattened list. The nodes in the list must have all of their child pointers set to null.

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 shown.
After flattening the multilevel linked list it becomes:

Example 2:

Input: head = [1,2,null,3]
Output: [1,3,2]
Explanation: The multilevel linked list in the input is shown.
After flattening the multilevel linked list it becomes:

Example 3:

Input: head = []
Output: []
Explanation: There could be empty list in the input.

Constraints:

  • The number of Nodes will not exceed 1000.
  • 1 <= Node.val <= 105

How the multilevel linked list is represented in test cases:

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]

Approach overview

Problem Overview: You are given a doubly linked list where each node may contain a child pointer to another doubly linked list. These child lists can also have their own children, forming multiple levels. The goal is to flatten the structure so every node appears in a single-level doubly linked list following depth-first order while preserving the prev and next relationships.

Approach 1: Iterative Using Stack (O(n) time, O(n) space)

This method simulates a depth-first traversal using an explicit stack. Start from the head and iterate through the list. When you encounter a node with a child, push the current node’s next pointer onto the stack, connect the child list as the next node, and continue traversal. When the traversal reaches the end of a child chain, pop from the stack and reconnect the saved node. Each node is processed exactly once, so the time complexity is O(n), and the stack can hold up to O(n) nodes in the worst case. This approach is practical when you want predictable control over traversal without recursion.

Approach 2: Recursive Depth-First Search (O(n) time, O(d) space)

The recursive strategy performs a DFS over the multilevel structure. For each node, recursively flatten its child list before continuing to the next node. The key step is reconnecting pointers: attach the flattened child between the current node and its original next, then connect the tail of the child list back to the saved next node. The recursion naturally processes nodes in depth-first order. The algorithm runs in O(n) time because every node is visited once, while the recursion stack consumes O(d) space where d is the maximum depth of nesting.

Both solutions rely on careful pointer manipulation typical in linked list problems. The traversal itself follows a depth-first search pattern, and maintaining correct prev/next relationships is essential when working with a doubly-linked list.

Recommended for interviews: The iterative stack approach is commonly preferred because it avoids recursion limits and clearly demonstrates control over pointer updates. Showing the recursive DFS solution first can demonstrate conceptual understanding of the depth-first structure, but implementing the stack-based version often signals stronger mastery of linked list manipulation.

Approach 1: Iterative Approach Using Stack

In this approach, we utilize a stack to achieve depth-first traversal of the multilevel doubly linked list. We push nodes into the stack starting from the head, along with managing the child nodes as higher priority over next nodes. This ensures that we process all child nodes before moving on to the next nodes.

class Solution:
    def flatten(self, head: 'Node') -> 'Node':
        if not head:
            return head

        stack = []
        curr = head

        while curr:
            if curr.child:
                if curr.next:
                    stack.append(curr.next)
                curr.next = curr.child
                curr.next.prev = curr
                curr.child = None
            
            if not curr.next and stack:
                curr.next = stack.pop()
                if curr.next:
                    curr.next.prev = curr

            curr = curr.next

        return head
import java.util.Stack;

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

        Stack<Node> stack = new Stack<>();
        Node curr = head;

        while (curr != null) {
            if (curr.child != null) {
                if (curr.next != null) stack.push(curr.next);
                curr.next = curr.child;
                curr.child.prev = curr;
                curr.child = null;
            }
            
            if (curr.next == null && !stack.isEmpty()) {
                curr.next = stack.pop();
                if (curr.next != null) curr.next.prev = curr;
            }

            curr = curr.next;
        }

        return head;
    }
}
#include <stack>

class Solution {
public:
    Node* flatten(Node* head) {
        if (!head) return head;
        std::stack<Node*> stk;
        Node* curr = head;
        
        while (curr) {
            if (curr->child) {
                if (curr->next) stk.push(curr->next);
                curr->next = curr->child;
                curr->next->prev = curr;
                curr->child = nullptr;
            }
            
            if (!curr->next && !stk.empty()) {
                curr->next = stk.top();
                stk.pop();
                if (curr->next) curr->next->prev = curr;
            }
            curr = curr->next;
        }
        
        return head;
    }
};
function flatten(head) {
    if (!head) return head;

    let stack = [];
    let curr = head;

    while (curr) {
        if (curr.child) {
            if (curr.next) stack.push(curr.next);
            curr.next = curr.child;
            curr.next.prev = curr;
            curr.child = null;
        }

        if (!curr.next && stack.length > 0) {
            curr.next = stack.pop();
            if (curr.next) curr.next.prev = curr;
        }

        curr = curr.next;
    }

    return head;
}
#include <stdlib.h>

struct Node {
    int val;
    struct Node* next;
    struct Node* prev;
    struct Node* child;
};

struct Node* flatten(struct Node* head) {
    if (!head) return head;
    struct Node* ptr = head;
    struct Node* stack[1000];
    int top = -1;

    while (ptr) {
        if (ptr->child) {
            if (ptr->next) {
                stack[++top] = ptr->next;
            }
            ptr->next = ptr->child;
            ptr->next->prev = ptr;
            ptr->child = NULL;
        } else if (!ptr->next && top != -1) {
            ptr->next = stack[top--];
            if (ptr->next) {
                ptr->next->prev = ptr;
            }
        }
        ptr = ptr->next;
    }

    return head;
}
using System.Collections.Generic;

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

        Stack<Node> stack = new Stack<Node>();
        Node curr = head;

        while (curr != null) {
            if (curr.child != null) {
                if (curr.next != null) stack.Push(curr.next);
                curr.next = curr.child;
                curr.child.prev = curr;
                curr.child = null;
            }

            if (curr.next == null && stack.Count > 0) {
                curr.next = stack.Pop();
                if (curr.next != null) curr.next.prev = curr;
            }

            curr = curr.next;
        }

        return head;
    }
}

The Python solution employs a straightforward stack approach, easily manipulating the stack to remember and resume positions in the linked list after processing child nodes.

Complexity

Time Complexity: O(n) as each node is visited once.
Space Complexity: O(n) because the stack structure may grow to hold all nodes in the worst case.

Try this approach in the editor

Approach 2: Recursive Approach

This approach utilizes recursion to handle the traversing and flattening of lists. By inherently using the function call stack, it efficiently manages shifts between the parent and child lists, automatically flattening the entire structure as it recursively resolves each node and its children.

class Solution:
    def flatten(self, head: 'Optional[Node]') -> 'Optional[Node]':
        if not head:
            return head

        self.flattenDFS(head)
        return head

    def flattenDFS(self, node: 'Node') -> 'Optional[Node]':
        curr = node
        tail = node

        while curr:
            next_node = curr.next
            if curr.child:
                child_tail = self.flattenDFS(curr.child)
                curr.next = curr.child
                curr.child.prev = curr
                curr.child = None

                if next_node:
                    child_tail.next = next_node
                    next_node.prev = child_tail
                
                tail = child_tail
            else:
                tail = curr
            curr = next_node

        return tail
class Solution {
    public Node flatten(Node head) {
        if (head == null) return head;
        flattenDFS(head);
        return head;
    }
    
    private Node flattenDFS(Node node) {
        Node curr = node;
        Node tail = node;

        while (curr != null) {
            Node next = curr.next;
            
            if (curr.child != null) {
                Node childTail = flattenDFS(curr.child);
                curr.next = curr.child;
                curr.child.prev = curr;
                curr.child = null;

                if (next != null) {
                    childTail.next = next;
                    next.prev = childTail;
                }
                tail = childTail;
            } else tail = curr;

            curr = next;
        }

        return tail;
    }
}
class Solution {
public:
    Node* flatten(Node* head) {
        if (!head) return head;
        
        flattenRec(head);
        return head;
    }
private:
    Node* flattenRec(Node* node) {
        Node* curr = node;
        Node* tail = node;
        
        while (curr) {
            Node* nextNode = curr->next;
            
            if (curr->child) {
                Node* childTail = flattenRec(curr->child);
                
                curr->next = curr->child;
                curr->next->prev = curr;
                curr->child = nullptr;
                
                if (nextNode) {
                    childTail->next = nextNode;
                    nextNode->prev = childTail;
                }
                tail = childTail;
            } else tail = curr;

            curr = nextNode;
        }
        return tail;
    }
};
function flatten(head) {
    if (!head) return head;

    function flattenDFS(node) {
        let curr = node;
        let tail = node;

        while (curr) {
            const next = curr.next;
            
            if (curr.child) {
                const childTail = flattenDFS(curr.child);
                curr.next = curr.child;
                curr.child.prev = curr;
                curr.child = null;

                if (next) {
                    childTail.next = next;
                    next.prev = childTail;
                }

                tail = childTail;
            } else {
                tail = curr;
            }

            curr = next;
        }
        return tail;
    }

    flattenDFS(head);
    return head;
}
#include <stdlib.h>

struct Node {
    int val;
    struct Node* next;
    struct Node* prev;
    struct Node* child;
};

struct Node* flatten(struct Node* head) {
    if (!head) return head;

    struct Node* flatten_rec(struct Node* head, struct Node** tail) {
        struct Node* curr = head;

        while (curr) {
            *tail = curr;
            struct Node* next = curr->next;

            if (curr->child) {
                struct Node* child_tail = NULL;
                curr->next = flatten_rec(curr->child, &child_tail);
                curr->next->prev = curr;
                curr->child = NULL;
                
                if (next) {
                    child_tail->next = next;
                    next->prev = child_tail;
                }
                
                *tail = child_tail;
            }

            curr = next;
        }

        return head;
    }

    struct Node* tail = NULL;
    return flatten_rec(head, &tail);
}
public class Solution {
    public Node Flatten(Node head) {
        if (head == null) return head;
        
        FlattenDFS(head);
        return head;
    }
    
    private Node FlattenDFS(Node node) {
        Node curr = node;
        Node tail = node;

        while (curr != null) {
            Node nextNode = curr.next;
            
            if (curr.child != null) {
                Node childTail = FlattenDFS(curr.child);
                curr.next = curr.child;
                curr.child.prev = curr;
                curr.child = null;

                if (nextNode != null) {
                    childTail.next = nextNode;
                    nextNode.prev = childTail;
                }

                tail = childTail;
            } else {
                tail = curr;
            }
            curr = nextNode;
        }

        return tail;
    }
}

The Python approach leverages recursion through 'flattenDFS' to break down the multilevel nodes into simpler, flat arrangements, dynamically patching lists together by handling next node linkage.

Complexity

Time Complexity: O(n), through singular node visits.
Space Complexity: O(d), weighed upon recursion depth impact.

Try this approach in the editor

Complexity comparison

ApproachComplexity
Iterative Approach Using Stack

Time Complexity: O(n) as each node is visited once.
Space Complexity: O(n) because the stack structure may grow to hold all nodes in the worst case.

Recursive Approach

Time Complexity: O(n), through singular node visits.
Space Complexity: O(d), weighed upon recursion depth impact.

Complexity analysis

ApproachTimeSpaceWhen to Use
Iterative Using StackO(n)O(n)Preferred in interviews when you want explicit control over traversal and avoid recursion depth limits
Recursive DFSO(n)O(d)Clean and intuitive when modeling the problem as depth-first traversal of nested lists

Frequently asked questions

Is Flatten a Multilevel Doubly Linked List easy or hard?

The problem is rated Medium because the traversal itself is straightforward, but pointer manipulation can easily introduce bugs. Correctly reconnecting prev, next, and child links while preserving order is the main challenge.

Flatten a Multilevel Doubly Linked List Python/Java solution

Both Python and Java implementations typically follow the same logic: iterate through nodes, attach child lists when encountered, and reconnect saved next nodes using a stack or recursion. The algorithm runs in O(n) time and works identically across C++, Java, Python, and JavaScript.

How to solve Flatten a Multilevel Doubly Linked List in O(n)?

Traverse the list using depth-first order. When a node has a child, store its next pointer, connect the child as the next node, and continue flattening the child list. After finishing the child chain, reconnect the stored next node. Using a stack or recursion ensures every node is processed once for O(n) time.

What is the best approach for Flatten a Multilevel Doubly Linked List?

The most practical approach is an iterative depth-first traversal using a stack. Each time a node with a child is found, the current next node is pushed onto the stack and the child list is attached as the next node. This processes every node once and maintains correct prev/next links, giving O(n) time complexity.

Is Flatten a Multilevel Doubly Linked List asked at Google/Amazon/Meta?

Multilevel linked list problems and pointer manipulation questions frequently appear in interviews at companies like Amazon, Meta, and Google. This problem tests understanding of depth-first traversal combined with careful doubly linked list pointer updates.

What data structure is used in Flatten a Multilevel Doubly Linked List?

The core structure is a doubly linked list where each node contains prev, next, and child pointers. Many implementations also use a stack to manage nodes that need to be revisited during depth-first traversal.

What is the time complexity of Flatten a Multilevel Doubly Linked List?

The optimal solutions run in O(n) time where n is the total number of nodes across all levels. Each node is visited and reconnected exactly once. Space complexity is O(n) for the stack-based approach or O(d) for the recursive solution where d is the maximum depth of nesting.

Comments

Now write it yourselfClose this page and solve Flatten a Multilevel Doubly Linked List in the editor, without looking.
Practise Flatten a Multilevel Doubly Linked List