Flatten a Multilevel Doubly Linked List
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ number of lists ≤ 50 - ◆
0 ≤ total nodes across every list ≤ 200 - ◆
-1000 ≤ node value ≤ 1000 - ◆
a list may attach as a child of any node in any other list — including another child list — so nesting depth is not bounded to one level
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — DFS Collect Every Value, Then Rebuild
GoodSince flattening always visits a node, then its entire child subtree (if any), then its own next node — a depth-first preorder walk — the simplest approach is to just record that visiting order into an array without touching any pointers, then build a brand new single-level list from the array afterward. Correct and easy to reason about, but it allocates an array (and a whole new chain of nodes) the size of the final flattened list.
O(n)O(n)1// Node definition used in this problem:
2// class Node {
3// int val;
4// Node next;
5// }
6
7class Solution {
8 static class MNode {
9 int val;
10 MNode next;
11 MNode prev;
12 MNode child;
13 MNode(int val) { this.val = val; }
14 }
15
16 private MNode buildChain(Node head) {
17 MNode dHead = null, dTail = null;
18 Node curr = head;
19 while (curr != null) {
20 MNode node = new MNode(curr.val);
21 if (dHead == null) {
22 dHead = node;
23 } else {
24 node.prev = dTail;
25 dTail.next = node;
26 }
27 dTail = node;
28 curr = curr.next;
29 }
30 return dHead;
31 }
32
33 private void collect(MNode head, List<Integer> out) {
34 MNode curr = head;
35 while (curr != null) {
36 out.add(curr.val);
37 if (curr.child != null) collect(curr.child, out);
38 curr = curr.next;
39 }
40 }
41
42 public Node flattenMultilevel(List<Node> lists, int[][] childOf) {
43 int n = lists.size();
44 MNode[] chains = new MNode[n];
45 for (int i = 0; i < n; i++) {
46 chains[i] = buildChain(lists.get(i));
47 }
48 for (int i = 0; i < childOf.length; i++) {
49 int parentIdx = childOf[i][0], pos = childOf[i][1];
50 MNode node = chains[parentIdx];
51 for (int k = 0; k < pos; k++) node = node.next;
52 node.child = chains[i + 1];
53 }
54 List<Integer> values = new ArrayList<>();
55 if (n > 0 && chains[0] != null) collect(chains[0], values);
56 Node dummy = new Node(0);
57 Node tail = dummy;
58 for (int v : values) {
59 tail.next = new Node(v);
60 tail = tail.next;
61 }
62 return dummy.next;
63 }
64}Optimal — Recursive DFS, Splice In Place
OptimalNo copy is needed at all. Recursively flatten a node's child list first (which itself may have children — this is where the recursion pays off, since a nested child's child gets flattened before it's ever spliced anywhere). Then splice that already-flat child chain directly between the node and whatever originally came after it, and continue walking from there. Each node is visited once, and every splice reuses the node objects that already exist — no rebuilding.
O(n)O(1) extra1// Node definition used in this problem:
2// class Node {
3// int val;
4// Node next;
5// }
6
7class Solution {
8 static class MNode {
9 int val;
10 MNode next;
11 MNode prev;
12 MNode child;
13 MNode(int val) { this.val = val; }
14 }
15
16 private MNode buildChain(Node head) {
17 MNode dHead = null, dTail = null;
18 Node curr = head;
19 while (curr != null) {
20 MNode node = new MNode(curr.val);
21 if (dHead == null) {
22 dHead = node;
23 } else {
24 node.prev = dTail;
25 dTail.next = node;
26 }
27 dTail = node;
28 curr = curr.next;
29 }
30 return dHead;
31 }
32
33 private MNode flatten(MNode head) {
34 MNode curr = head;
35 MNode tail = head;
36 while (curr != null) {
37 MNode next = curr.next;
38 if (curr.child != null) {
39 MNode childTail = flatten(curr.child);
40 curr.next = curr.child;
41 curr.child.prev = curr;
42 curr.child = null;
43 childTail.next = next;
44 if (next != null) next.prev = childTail;
45 tail = childTail;
46 } else {
47 tail = curr;
48 }
49 curr = next;
50 }
51 return tail;
52 }
53
54 public Node flattenMultilevel(List<Node> lists, int[][] childOf) {
55 int n = lists.size();
56 MNode[] chains = new MNode[n];
57 for (int i = 0; i < n; i++) {
58 chains[i] = buildChain(lists.get(i));
59 }
60 for (int i = 0; i < childOf.length; i++) {
61 int parentIdx = childOf[i][0], pos = childOf[i][1];
62 MNode node = chains[parentIdx];
63 for (int k = 0; k < pos; k++) node = node.next;
64 node.child = chains[i + 1];
65 }
66 if (n == 0 || chains[0] == null) return null;
67 flatten(chains[0]);
68 Node dummy = new Node(0);
69 Node tail = dummy;
70 MNode c = chains[0];
71 while (c != null) {
72 tail.next = new Node(c.val);
73 tail = tail.next;
74 c = c.next;
75 }
76 return dummy.next;
77 }
78}