Facebook Pixel

3263. Convert Doubly Linked List to Array I 🔒

EasyArrayLinked ListDoubly-Linked List
Leetcode Link

Problem Description

You are given the head of a doubly linked list. A doubly linked list is a data structure where each node contains:

  • A value (val)
  • A pointer to the next node (next)
  • A pointer to the previous node (prev)

Your task is to traverse the linked list starting from the head and return an integer array that contains all the values of the nodes in order from head to tail.

For example, if the doubly linked list is 1 ↔ 2 ↔ 3 ↔ 4, you should return the array [1, 2, 3, 4].

The solution traverses the linked list from the head node, visiting each node sequentially using the next pointer. At each node, the value is added to a result array. The traversal continues until reaching the end of the list (when root becomes None). Finally, the array containing all node values in order is returned.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to convert a doubly linked list into an array. The most natural way to think about this is to follow how we would manually read through the list: start at the beginning and visit each node one by one until we reach the end.

Since we need the elements "in order" and we're given the head of the list, we should traverse forward using the next pointers. Even though this is a doubly linked list with prev pointers as well, we don't need to use them for this problem - we can treat it just like a regular singly linked list traversal.

The key insight is that we simply need to:

  1. Start at the head node
  2. Record the current node's value
  3. Move to the next node
  4. Repeat until we've visited all nodes

This is a straightforward linear traversal pattern. We collect values as we go, storing them in an array that preserves the order of our traversal. When we can't move forward anymore (when root becomes None), we know we've reached the end of the list and have collected all values.

The simplicity of this approach comes from recognizing that converting a linked structure to an array is fundamentally about visiting each element exactly once in the correct order, which a basic traversal naturally accomplishes.

Learn more about Linked List patterns.

Solution Approach

The solution uses a direct traversal approach to convert the doubly linked list into an array. Here's how the implementation works:

Algorithm Steps:

  1. Initialize an empty result array: We create an empty list ans = [] that will store the values from the linked list nodes.

  2. Traverse the linked list: We use a while loop with the condition while root: to continue traversing as long as we haven't reached the end of the list (when root becomes None).

  3. Collect node values: Inside the loop, we:

    • Append the current node's value to our result array: ans.append(root.val)
    • Move to the next node: root = root.next
  4. Return the result: After the traversal completes, we return the ans array containing all node values in order.

Data Structure Used:

  • We use a Python list (ans) to store the values, which provides O(1) amortized time for append operations.

Pattern: This is a classic linked list traversal pattern. The code follows the standard template for iterating through a linked list:

while current_node:
    # Process current node
    current_node = current_node.next

Time and Space Complexity:

  • Time Complexity: O(n), where n is the number of nodes in the linked list. We visit each node exactly once.
  • Space Complexity: O(n) for storing the n values in the result array. The traversal itself only uses O(1) extra space for the pointer.

The beauty of this solution lies in its simplicity - we don't need to use the prev pointers at all, and the forward traversal naturally gives us the elements in the correct order.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with a small doubly linked list: 10 ↔ 20 ↔ 30

Initial State:

  • head points to the first node with value 10
  • ans = [] (empty result array)
  • root = head (our traversal pointer starts at the head)

Step 1: Process first node (value = 10)

  • Check: root is not None, so we enter the loop
  • Append root.val (10) to ans: ans = [10]
  • Move forward: root = root.next (now points to node with value 20)

Step 2: Process second node (value = 20)

  • Check: root is not None, so we continue
  • Append root.val (20) to ans: ans = [10, 20]
  • Move forward: root = root.next (now points to node with value 30)

Step 3: Process third node (value = 30)

  • Check: root is not None, so we continue
  • Append root.val (30) to ans: ans = [10, 20, 30]
  • Move forward: root = root.next (now root = None since this was the last node)

Step 4: Exit loop

  • Check: root is None, so we exit the while loop
  • Return ans = [10, 20, 30]

The algorithm successfully traversed the entire linked list from head to tail, collecting each value in order. Notice how we only used the next pointers to move forward through the list - the prev pointers weren't needed for this traversal.

Solution Implementation

1"""
2# Definition for a Node.
3class Node:
4    def __init__(self, val, prev=None, next=None):
5        self.val = val
6        self.prev = prev
7        self.next = next
8"""
9
10from typing import List, Optional
11
12
13class Solution:
14    def toArray(self, root: Optional['Node']) -> List[int]:
15        """
16        Convert a doubly linked list to an array.
17      
18        Args:
19            root: The head node of the doubly linked list.
20          
21        Returns:
22            A list containing all values from the linked list in order.
23        """
24        # Initialize an empty list to store the values
25        result = []
26      
27        # Traverse the linked list from head to tail
28        current_node = root
29        while current_node:
30            # Add the current node's value to the result list
31            result.append(current_node.val)
32            # Move to the next node
33            current_node = current_node.next
34          
35        return result
36
1/*
2// Definition for a Node.
3class Node {
4    public int val;
5    public Node prev;
6    public Node next;
7};
8*/
9
10class Solution {
11    /**
12     * Converts a doubly linked list to an integer array.
13     * 
14     * @param head The head node of the doubly linked list
15     * @return An integer array containing all values from the linked list in order
16     */
17    public int[] toArray(Node head) {
18        // Create a list to store all node values
19        List<Integer> resultList = new ArrayList<>();
20      
21        // Traverse the linked list from head to tail
22        Node currentNode = head;
23        while (currentNode != null) {
24            // Add current node's value to the list
25            resultList.add(currentNode.val);
26            // Move to the next node
27            currentNode = currentNode.next;
28        }
29      
30        // Convert the list to an integer array and return
31        return resultList.stream()
32                         .mapToInt(Integer::intValue)
33                         .toArray();
34    }
35}
36
1/**
2 * Definition for doubly-linked list.
3 * class Node {
4 *     int val;
5 *     Node* prev;
6 *     Node* next;
7 *     Node() : val(0), next(nullptr), prev(nullptr) {}
8 *     Node(int x) : val(x), next(nullptr), prev(nullptr) {}
9 *     Node(int x, Node *prev, Node *next) : val(x), next(next), prev(prev) {}
10 * };
11 */
12class Solution {
13public:
14    /**
15     * Converts a doubly-linked list to a vector array
16     * @param head - pointer to the head node of the doubly-linked list
17     * @return vector containing all values from the linked list in order
18     */
19    vector<int> toArray(Node* head) {
20        // Initialize result vector to store the linked list values
21        vector<int> result;
22      
23        // Traverse the linked list from head to tail
24        // Continue until we reach the end (nullptr)
25        for (Node* current = head; current != nullptr; current = current->next) {
26            // Add current node's value to the result vector
27            result.push_back(current->val);
28        }
29      
30        // Return the populated vector
31        return result;
32    }
33};
34
1/**
2 * Definition for _Node.
3 * class _Node {
4 *     val: number
5 *     prev: _Node | null
6 *     next: _Node | null
7 *
8 *     constructor(val?: number, prev? : _Node, next? : _Node) {
9 *         this.val = (val===undefined ? 0 : val);
10 *         this.prev = (prev===undefined ? null : prev);
11 *         this.next = (next===undefined ? null : next);
12 *     }
13 * }
14 */
15
16/**
17 * Converts a doubly linked list to an array of values
18 * @param head - The head node of the doubly linked list
19 * @returns An array containing all values from the linked list in order
20 */
21function toArray(head: _Node | null): number[] {
22    // Initialize result array to store node values
23    const result: number[] = [];
24  
25    // Traverse the linked list from head to tail
26    let currentNode: _Node | null = head;
27    while (currentNode !== null) {
28        // Add current node's value to the result array
29        result.push(currentNode.val);
30        // Move to the next node
31        currentNode = currentNode.next;
32    }
33  
34    return result;
35}
36

Time and Space Complexity

Time Complexity: O(n), where n is the length of the linked list. The algorithm traverses through each node exactly once, visiting all n nodes in the list sequentially. Each operation inside the loop (appending to the list and moving to the next node) takes O(1) time, resulting in a total time complexity of O(n).

Space Complexity: O(1) if we exclude the space used by the output array ans. The algorithm only uses a constant amount of extra space for the pointer variable root that traverses the list. The space consumed by the answer array itself is O(n) since it stores all n values from the linked list, but following the convention stated in the reference answer, this is not counted toward the space complexity as it is required for the output.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Modifying the Input Parameter Name

One common pitfall is accidentally modifying the input parameter name (like using root instead of the original parameter name) and forgetting to update all references, leading to NameError exceptions.

Problematic Code:

def toArray(self, root: Optional['Node']) -> List[int]:
    result = []
    while head:  # Error: 'head' is not defined
        result.append(head.val)
        head = head.next
    return result

Solution: Use consistent naming throughout the function. Either rename the parameter or use a separate variable:

def toArray(self, root: Optional['Node']) -> List[int]:
    result = []
    current = root  # Create a separate traversal pointer
    while current:
        result.append(current.val)
        current = current.next
    return result

2. Not Handling None/Empty List

While the provided solution handles this correctly with while current_node:, beginners might write code that doesn't properly check for an empty list.

Problematic Code:

def toArray(self, root: Optional['Node']) -> List[int]:
    result = [root.val]  # Error if root is None
    current = root.next
    while current:
        result.append(current.val)
        current = current.next
    return result

Solution: Always check if the head is None before accessing its properties.

3. Infinite Loop Due to Circular References

In real-world scenarios, a corrupted doubly linked list might have circular references. The standard traversal would result in an infinite loop.

Solution with Cycle Detection:

def toArray(self, root: Optional['Node']) -> List[int]:
    result = []
    visited = set()
    current = root
  
    while current:
        # Check for cycle
        if id(current) in visited:
            break  # or raise an exception for corrupted list
        visited.add(id(current))
      
        result.append(current.val)
        current = current.next
      
    return result

4. Accidentally Using the Previous Pointer

Since it's a doubly linked list, developers might mistakenly traverse backward or mix up the pointers.

Problematic Code:

def toArray(self, root: Optional['Node']) -> List[int]:
    result = []
    while root:
        result.append(root.val)
        root = root.prev  # Wrong direction!
    return result

Solution: Be explicit about the traversal direction and stick to using next for forward traversal.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

How would you design a stack which has a function min that returns the minimum element in the stack, in addition to push and pop? All push, pop, min should have running time O(1).


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More