Exploring Leetcode : Flatten a Multilevel Doubly Linked List

Abi FarhanAbi Farhan
8 min read

Introduction

Leetcode is a renowned platform that offers coding interviews and challenging algorithmic problems. Among its fascinating problem sets, there's one called "Flatten a Multilevel Doubly Linked List." This particular problem involves working with a doubly linked list where each node can contain a child-linked list, forming a multilevel structure. The objective is to flatten the list, eliminating the nested structure and transforming it into a single-level doubly linked list. Solving this problem requires a strong grasp of linked list manipulation and efficient problem-solving skills. In this discussion, we'll delve into the problem in detail and explore potential approaches to tackle it effectively.

Problem Overview

The Problem Overview for "Flatten a Multilevel Doubly Linked List" can be better understood by referring to the provided illustration on the official LeetCode website. You can access the illustration and detailed description of the problem at the following link: https://leetcode.com/problems/flatten-a-multilevel-doubly-linked-list/description/

Approach Solution

Before discussing the approach, let's take a look at the code solution.

var flatten = function(head) {
  if (!head) return head;

    let currentNode = head;
    while (currentNode !== null) {
        if (currentNode.child === null) {
            currentNode = currentNode.next;
        } else {
            let tail = currentNode.child;
            while (tail.next !== null) {
                tail = tail.next;
            }

            tail.next = currentNode.next;
            if (tail.next !== null) {
                tail.next.prev = tail;
            }

            currentNode.next = currentNode.child;
            currentNode.next.prev = currentNode;
            currentNode.child = null;
        }
    }

    return head;
};

If you didn't fully understand it, don't worry. Here's an explanation to help clarify things for you.

  1. The flatten function takes the head node of a multilevel doubly linked list as input and returns the flattened list.

  2. The code first checks if the head node is null. If it is, it immediately returns the head itself since there is no list to flatten.

  3. The code uses a while loop to iterate through each node of the list starting from the head.

  4. Inside the loop, it checks if the current node has a child. If it does not have a child, it simply moves to the next node by updating the currentNode variable to currentNode.next.

  5. If the current node has a child, the code enters the else block. It starts by finding the tail of the child list by iterating through the child nodes using a while loop.

  6. Once the tail of the child list is found, the code performs the necessary pointer manipulations to integrate the child list into the main list. It connects the tail of the child list to the next node of the current node, ensuring the order is maintained. It also updates the previous pointers accordingly.

  7. After integrating the child list, the code sets the currentNode.next pointer to the child list. It also updates the previous pointer of the new next node to currentNode.

  8. Finally, the code sets the currentNode.child to null since the child list has been flattened and no longer exists.

  9. The while loop continues until all nodes in the list have been processed.

  10. Finally, the function returns the head of the flattened list.

Test Case

To make you understand solid, you can refer this some test cases

  1. Test Case: Empty List Input: null Expected Output: null

  2. Test Case: Single Node Input: { val: 1, prev: null, next: null, child: null } Expected Output: { val: 1, prev: null, next: null, child: null }

  3. Test Case: Flat List Input: { val: 1, prev: null, next: { val: 2, prev: null, next: { val: 3, prev: null, next: null, child: null }, child: null }, child: null } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: { val: 3, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }

  4. Test Case: Multilevel List Input: { val: 1, prev: null, next: { val: 2, prev: null, next: { val: 3, prev: null, next: null, child: null }, child: { val: 4, prev: null, next: { val: 5, prev: null, next: null, child: null }, child: null } }, child: null } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: { val: 4, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: { val: 5, prev: { val: 4, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }, child: null }

  5. Test Case: List with a Single Child Input: { val: 1, prev: null, next: { val: 2, prev: null, next: null, child: { val: 3, prev: null, next: null, child: null } }, child: null } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: { val: 3, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }

  6. Test Case: List with Multiple Levels of Children Input: { val: 1, prev: null, next: { val: 2, prev: null, next: null, child: { val: 3, prev: null, next: null, child: { val: 4, prev: null, next: null, child: null } } }, child: { val: 5, prev: null, next: null, child: { val: 6, prev: null, next: null, child: null } } } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: { val: 5, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: { val: 6, prev: { val: 5, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }, child: { val: 3, prev: null, next: { val: 4, prev: { val: 3, prev: null, next: null, child: null }, next: null, child: null }, child: null } }

  7. Test Case: List with Empty Child Lists Input: { val: 1, prev: null, next: { val: 2, prev: null, next: { val: 3, prev: null, next: null, child: null }, child: { val: 4, prev: null, next: null, child: null } }, child: { val: 5, prev: null, next: null, child: null } } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: { val: 4, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }

  8. Test Case: List with No Child but with Prev Pointer Input: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, child: null } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, child: null }

  9. Test Case: List with No Child but with Next and Prev Pointers Input: { val: 1, prev: { val: 0, prev: null, next: { val: 1, prev: null, next: null, child: null }, child: null }, next: { val: 2, prev: { val: 1, prev: { val: 0, prev: null, next: { val: 1, prev: null, next: null, child: null }, child: null }, next: null, child: null }, next: null, child: null }, child: null } Expected Output: { val: 0, prev: null, next: { val: 1, prev: { val: 0, prev: null, next: { val: 1, prev: null, next: null, child: null }, child: null }, next: { val: 2, prev: { val: 1, prev: { val: 0, prev: null, next: { val: 1, prev: null, next: null, child: null }, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }

  10. Test Case: List with Complex Multilevel Structure Input: { val: 1, prev: null, next: { val: 2, prev: null, next: { val: 3, prev: null, next: null, child: null }, child: { val: 4, prev: null, next: { val: 5, prev: null, next: null, child: null }, child: null } }, child: { val: 6, prev: null, next: { val: 7, prev: null, next: null, child: null }, child: { val: 8, prev: null, next: { val: 9, prev: null, next: null, child: null }, child: null } } } Expected Output: { val: 1, prev: null, next: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: { val: 4, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: { val: 5, prev: { val: 4, prev: { val: 2, prev: { val: 1, prev: null, next: null, child: null }, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }, child: { val: 6, prev: null, next: { val: 7, prev: { val: 6, prev: null, next: { val: 8, prev: { val: 7, prev: { val: 6, prev: null, next: { val: 7, prev: null, next: null, child: null }, child: null }, next: null, child: null }, next: { val: 9, prev: { val: 8, prev: { val: 7, prev: { val: 6, prev: null, next: { val: 7, prev: null, next: null, child: null }, child: null }, next: null, child: null }, next: null, child: null }, next: null, child: null }, child: null }, child: null }, next: null, child: null }, child: null }

Conclusion

This approach effectively flattens the multilevel structure of the linked list by iterating through the nodes, identifying nodes with child lists, and integrating them into the main list. The necessary pointer manipulations ensure the correct connections between nodes, resulting in a flattened doubly linked list.

References

0
Subscribe to my newsletter

Read articles from Abi Farhan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Abi Farhan
Abi Farhan

Working professionally with high passion and curiosity about Entrepreneurship, Tech, and Coffee. I am willing to work hard, learn faster, and extremely fast adaptation to new tech stacks. I have more 3 years of experience as a Software Engineer in the Industry world and academic world, I believe with my experience combined with my abilities as an Entrepreneur and Software Engineer with a deep understanding of data structure and algorithms also as strong skills for problem-solving would make me a valuable asset too much technology-oriented business seeking the talent with always hungry for knowledge and always eager to learn new things. For now, I work as Software Engineer in Aleph-Labs which develop the MyXL Ultimate app also I develop my own business Gayo Coffee Engaged in B2B and B2C. I am also Bilingual Communicator (English, Indonesia) with experience public speaker and leadership. I also experiece management project using Jira and Notion, also strong skills for teamwork including deep knowledge about Version Control System like Git.