Add Two Numbers Represented as Linked List in DSA Rust - Time & Space Complexity
We want to understand how the time needed to add two numbers stored as linked lists grows as the numbers get longer.
How does the work increase when the linked lists have more digits?
Analyze the time complexity of the following code snippet.
fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut p = l1;
let mut q = l2;
let mut carry = 0;
let mut dummy_head = Box::new(ListNode::new(0));
let mut current = &mut dummy_head;
while p.is_some() || q.is_some() {
let x = p.as_ref().map_or(0, |node| node.val);
let y = q.as_ref().map_or(0, |node| node.val);
let sum = carry + x + y;
carry = sum / 10;
current.next = Some(Box::new(ListNode::new(sum % 10)));
current = current.next.as_mut().unwrap();
if let Some(node) = p.as_mut() { p = node.next.take(); }
if let Some(node) = q.as_mut() { q = node.next.take(); }
}
if carry > 0 {
current.next = Some(Box::new(ListNode::new(carry)));
}
dummy_head.next
}
This code adds two numbers digit by digit, moving through each linked list once.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single while loop that moves through both linked lists.
- How many times: The loop runs once for each digit in the longer linked list.
As the number of digits (nodes) in the linked lists grows, the number of steps grows roughly the same.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The work grows linearly with the number of digits.
Time Complexity: O(n)
This means the time to add the numbers grows directly in proportion to the number of digits.
[X] Wrong: "The time complexity is O(n²) because we add digits multiple times."
[OK] Correct: Each digit is processed only once in a single pass, so the work grows linearly, not quadratically.
Understanding this linear time complexity helps you explain how to efficiently add numbers stored in linked lists, a common problem that shows your grasp of list traversal and simple arithmetic operations.
"What if the digits were stored in forward order instead of reverse? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem context
The problem involves two linked lists where each node contains a single digit of a number, stored in reverse order.Step 2: Identify the required operation
We need to add these two numbers digit by digit, handling carry, and return the sum as a linked list.Final Answer:
Adding two numbers where each digit is stored in a node of a linked list -> Option BQuick Check:
Adding digits node-wise = Adding two numbers where each digit is stored in a node of a linked list [OK]
- Confusing addition with merging or sorting
- Ignoring the carry between digits
- Assuming digits are stored in forward order
Solution
Step 1: Recall Rust linked list node structure
Each node holds a value and an optional pointer to the next node using Box wrapped in Option for possible None.Step 2: Check each option
struct ListNode { val: i32, next: Option } uses Option which is correct. struct ListNode { val: i32, next: ListNode } and D lack Option, causing infinite size. struct ListNode { val: i32, next: &ListNode } uses reference which is invalid for ownership.Final Answer:
struct ListNode { val: i32, next: Option } -> Option CQuick Check:
Use Option for linked list nodes in Rust [OK]
- Using direct ListNode type for next causing infinite size
- Using references without lifetime annotations
- Omitting Option causing no None termination
Solution
Step 1: Add digits with carry
2+5=7 (carry 0), 4+6=10 (carry 1), 3+4+1=8 (carry 0)Step 2: Form the resulting linked list
Digits are 7 -> 0 -> 8 representing 807 in reverse order.Final Answer:
7 -> 0 -> 8 -> Option DQuick Check:
342 + 465 = 807 reversed as 7->0->8 [OK]
- Not carrying over when sum >= 10
- Mixing digit order in output
- Adding digits without carry
while l1.is_some() || l2.is_some() {
let sum = l1.unwrap().val + l2.unwrap().val + carry;
carry = sum / 10;
let node = ListNode::new(sum % 10);
// ...
}Solution
Step 1: Analyze unwrap usage
unwrap() on Option without checking Some causes panic if None occurs.Step 2: Check loop condition and unwrap safety
Loop runs while either list is Some, but unwrap is called on both without checking, causing runtime error.Final Answer:
Calling unwrap() without checking if Option is Some causes panic -> Option AQuick Check:
Always check Option before unwrap to avoid panic [OK]
- Assuming both lists have same length without checks
- Ignoring Option safety causing runtime panic
- Incorrect loop condition logic
Solution
Step 1: Understand unequal length addition
When one list ends, continue adding remaining digits of longer list plus carry.Step 2: Maintain carry and process all nodes
Carry from previous additions must be added until no nodes or carry remain.Final Answer:
Continue adding remaining digits of longer list with carry until all nodes processed -> Option AQuick Check:
Process all digits and carry regardless of list lengths [OK]
- Stopping addition early ignoring leftover digits
- Not adding carry after lists end
- Reversing lists unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
