class Node:
def __init__(self, val, prev=None, next=None, child=None):
self.val = val
self.prev = prev
self.next = next
self.child = child
class Solution:
def flatten(self, head: 'Node') -> 'Node':
def flatten_rec(node):
curr = node
last = node
while curr:
nxt = curr.next
if curr.child:
child_head = curr.child
child_tail = flatten_rec(child_head)
curr.next = child_head
child_head.prev = curr
if nxt:
child_tail.next = nxt
nxt.prev = child_tail
curr.child = None
last = child_tail
else:
last = curr
curr = nxt
return last
flatten_rec(head)
return head
/*
// Definition for a Node.
class Node {
public:
int val;
Node* prev;
Node* next;
Node* child;
};
*/
class Solution {
public:
Node* flatten(Node* head) {
flattenDFS(head);
return head;
}
Node* flattenDFS(Node* node) {
Node* curr = node;
Node* last = node;
while (curr) {
Node* nxt = curr->next;
if (curr->child) {
Node* child_head = curr->child;
Node* child_tail = flattenDFS(child_head);
curr->next = child_head;
child_head->prev = curr;
if (nxt) {
child_tail->next = nxt;
nxt->prev = child_tail;
}
curr->child = nullptr;
last = child_tail;
} else {
last = curr;
}
curr = nxt;
}
return last;
}
};
/*
// Definition for a Node.
class Node {
public int val;
public Node prev;
public Node next;
public Node child;
};
*/
class Solution {
public Node flatten(Node head) {
flattenDFS(head);
return head;
}
private Node flattenDFS(Node node) {
Node curr = node;
Node last = node;
while (curr != null) {
Node nxt = curr.next;
if (curr.child != null) {
Node childHead = curr.child;
Node childTail = flattenDFS(childHead);
curr.next = childHead;
childHead.prev = curr;
if (nxt != null) {
childTail.next = nxt;
nxt.prev = childTail;
}
curr.child = null;
last = childTail;
} else {
last = curr;
}
curr = nxt;
}
return last;
}
}
/**
* // Definition for a Node.
* function Node(val, prev, next, child) {
* this.val = val;
* this.prev = prev;
* this.next = next;
* this.child = child;
* };
*/
/**
* @param {Node} head
* @return {Node}
*/
var flatten = function(head) {
function flattenDFS(node) {
let curr = node;
let last = node;
while (curr) {
let nxt = curr.next;
if (curr.child) {
let childHead = curr.child;
let childTail = flattenDFS(childHead);
curr.next = childHead;
childHead.prev = curr;
if (nxt) {
childTail.next = nxt;
nxt.prev = childTail;
}
curr.child = null;
last = childTail;
} else {
last = curr;
}
curr = nxt;
}
return last;
}
flattenDFS(head);
return head;
};
You are given the head of a multilevel doubly linked list. Each node in this list contains:
val
prev
and next
to the previous and next nodes, respectivelychild
pointer that may point to another doubly linked list (the child list)
Your task is to flatten the list so that all nodes appear in a single-level, doubly linked list. The nodes should appear in a depth-first order: for each node, after itself, its child list (if any) should be inserted before its next node. All child
pointers must be set to null
in the flattened list.
Constraints:
When approaching this problem, the first idea that might come to mind is to traverse the list and, whenever a node has a child, insert the entire child list between the current node and its next node. This requires careful pointer manipulation to preserve the doubly linked nature and not lose track of the rest of the list.
A brute-force approach could be to collect all the nodes in a flat array, then reconstruct the list. However, this would violate the constraints of not using extra data structures and not creating new nodes.
Therefore, we need an in-place algorithm. The recursive nature of the multilevel structure suggests that a depth-first traversal would be effective. At each node, we process its child (if present) before moving to the next node. This way, we can "splice" the child list into the main list at the correct position.
The challenge is to keep track of the tail of the flattened child list so we can reconnect the next node properly. We also need to ensure that all child
pointers are set to null
after flattening.
The solution uses a recursive depth-first traversal to flatten the multilevel doubly linked list in place. Here’s a step-by-step breakdown:
next
pointer to the child, and set the child’s prev
to the current node.next
node, connect the tail of the child list to it, and set the next
node’s prev
to the child list’s tail.child
pointer to null
.This method ensures all nodes are visited exactly once, and all pointers are updated in place, without extra data structures.
Consider the following multilevel list:
Step-by-step:
The final flattened list is: 1-2-3-7-8-11-12-9-10-4-5-6
Brute-force approach:
No additional data structures are used beyond the recursion stack.
The problem of flattening a multilevel doubly linked list is elegantly solved using a recursive, depth-first traversal. The key insight is to process each child list in place, splicing it into the main list and updating all pointers as you go. This method respects all constraints: it does not use extra space (apart from the call stack), does not create new nodes, and guarantees the unique, correct order for the flattened list. The approach is efficient, easy to reason about, and leverages the recursive structure of the input data.