369. Plus One Linked List 🔒
Problem Description
You are given a non-negative integer that is represented as a singly linked list, where each node contains a single digit. The digits are arranged such that the most significant digit comes first (at the head of the list).
Your task is to add one to this integer and return the result as a linked list in the same format.
For example:
- If the linked list represents
1 -> 2 -> 3
(which represents the number 123), after adding one, it should become1 -> 2 -> 4
(representing 124). - If the linked list represents
9 -> 9 -> 9
(which represents the number 999), after adding one, it should become1 -> 0 -> 0 -> 0
(representing 1000).
The challenge involves handling the carry operation properly, especially when there are consecutive 9
s at the end of the number, as they will all become 0
with a carry propagating forward.
Intuition
When we add 1
to a number, the key insight is that we only need to handle the carry operation for consecutive 9
s at the end. Think about it: when you add 1
to 1299
, you get 1300
. The 9
s at the end all become 0
, and the last non-9
digit (which is 2
) becomes 3
.
This observation leads us to realize that we don't need to process the entire number digit by digit with carry propagation. Instead, we can find the rightmost digit that is not 9
, increment it by 1
, and then set all digits after it to 0
.
For example:
1234
+1
=1235
: The last non-9
is4
, we change it to5
1299
+1
=1300
: The last non-9
is2
, we change it to3
, and all9
s after it become0
999
+1
=1000
: All digits are9
, so we need an extra digit at the front
The tricky part is handling the edge case where all digits are 9
(like 999
). In this case, we need to add an extra digit 1
at the beginning. To handle this elegantly, we can use a dummy node with value 0
at the start. If all original digits are 9
, this dummy node will be incremented to 1
and become part of our answer. Otherwise, we can simply skip it when returning the result.
This approach is more efficient than simulating the actual addition with carry, as we only need to traverse the list once to find the critical position (the last non-9
digit) and then update the necessary nodes.
Solution Approach
The implementation uses a single traversal approach with a dummy node to handle edge cases elegantly.
Step 1: Set up a dummy node
We create a dummy node with value 0
and point it to the original head. This dummy node serves two purposes:
- It acts as a potential new most significant digit if all original digits are
9
- It provides a starting point for our target pointer
dummy = ListNode(0, head) target = dummy
Step 2: Find the rightmost non-9 digit
We traverse the entire linked list while maintaining a pointer target
that tracks the last node we encountered that isn't 9
. This is the node we'll need to increment.
while head:
if head.val != 9:
target = head
head = head.next
During this traversal:
- If we find a node with value not equal to
9
, we updatetarget
to point to it - We continue until we reach the end of the list
- After the loop,
target
points to the rightmost non-9
digit (or the dummy if all digits are9
)
Step 3: Increment and reset
Once we've identified the target node, we increment it by 1
and then set all nodes after it to 0
:
target.val += 1
target = target.next
while target:
target.val = 0
target = target.next
This handles the carry propagation - all 9
s after the incremented digit become 0
s.
Step 4: Return the result
Finally, we check if the dummy node was used (its value would be 1
if all original digits were 9
):
return dummy if dummy.val else dummy.next
- If
dummy.val
is1
, we returndummy
(we needed the extra digit) - Otherwise, we return
dummy.next
(the original head, now modified)
This approach runs in O(n)
time with a single pass through the list and uses O(1)
extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the input 1 -> 2 -> 9 -> 9
(representing 1299).
Step 1: Initialize with dummy node
dummy(0) -> 1 -> 2 -> 9 -> 9
target = dummy
We create a dummy node with value 0 pointing to the head, and initialize target
to point to dummy.
Step 2: Traverse to find rightmost non-9
- Start at node
1
:1 ≠ 9
, so updatetarget = node(1)
- Move to next node
- At node
2
:2 ≠ 9
, so updatetarget = node(2)
- Move to next node
- At node
9
:9 = 9
, so don't update target- Move to next node
- At node
9
:9 = 9
, so don't update target- Move to next node (null)
After traversal, target
points to node 2
(the rightmost non-9 digit).
Step 3: Increment target and set following nodes to 0
- Increment target: node
2
becomes3
- Move target to next node (first
9
) - Set to 0: first
9
becomes0
- Move target to next node (second
9
) - Set to 0: second
9
becomes0
- Move target to next node (null)
The list is now: dummy(0) -> 1 -> 3 -> 0 -> 0
Step 4: Return result
Since dummy.val = 0
(not 1), we return dummy.next
, which gives us:
1 -> 3 -> 0 -> 0
(representing 1300)
Edge Case Example: All 9s
For input 9 -> 9 -> 9
:
- After Step 2:
target
remains pointing todummy
(no non-9 found) - After Step 3:
dummy
becomes1
, all original nodes become0
- List becomes:
1 -> 0 -> 0 -> 0
- Since
dummy.val = 1
, we returndummy
itself
Solution Implementation
1# Definition for singly-linked list.
2# class ListNode:
3# def __init__(self, val=0, next=None):
4# self.val = val
5# self.next = next
6
7from typing import Optional
8
9class Solution:
10 def plusOne(self, head: Optional[ListNode]) -> Optional[ListNode]:
11 # Create a dummy node pointing to head to handle edge case where all digits are 9
12 dummy = ListNode(0, head)
13
14 # Find the rightmost node that is not 9
15 # This will be the node we increment
16 rightmost_not_nine = dummy
17 current = head
18
19 while current:
20 if current.val != 9:
21 rightmost_not_nine = current
22 current = current.next
23
24 # Increment the rightmost non-9 digit
25 rightmost_not_nine.val += 1
26
27 # Set all nodes after the incremented node to 0
28 # These were all 9s that need to become 0s due to carry
29 current = rightmost_not_nine.next
30 while current:
31 current.val = 0
32 current = current.next
33
34 # If dummy node was incremented (all original digits were 9), return dummy
35 # Otherwise, return the original head
36 return dummy if dummy.val else dummy.next
37
1/**
2 * Definition for singly-linked list.
3 * public class ListNode {
4 * int val;
5 * ListNode next;
6 * ListNode() {}
7 * ListNode(int val) { this.val = val; }
8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
9 * }
10 */
11class Solution {
12 public ListNode plusOne(ListNode head) {
13 // Create a dummy node pointing to head to handle potential carry to a new digit
14 ListNode dummyHead = new ListNode(0, head);
15
16 // Find the rightmost node that is not 9
17 // This will be the node we increment (to handle carry propagation efficiently)
18 ListNode lastNonNineNode = dummyHead;
19 ListNode current = head;
20
21 // Traverse the list to find the rightmost non-9 digit
22 while (current != null) {
23 if (current.val != 9) {
24 lastNonNineNode = current;
25 }
26 current = current.next;
27 }
28
29 // Increment the rightmost non-9 digit
30 lastNonNineNode.val++;
31
32 // Set all nodes after the incremented node to 0
33 // (these were all 9s that need to become 0s due to carry)
34 ListNode nodeToReset = lastNonNineNode.next;
35 while (nodeToReset != null) {
36 nodeToReset.val = 0;
37 nodeToReset = nodeToReset.next;
38 }
39
40 // If dummy head was incremented (from 0 to 1), we need a new leading digit
41 // Otherwise, return the original head
42 return dummyHead.val == 1 ? dummyHead : dummyHead.next;
43 }
44}
45
1/**
2 * Definition for singly-linked list.
3 * struct ListNode {
4 * int val;
5 * ListNode *next;
6 * ListNode() : val(0), next(nullptr) {}
7 * ListNode(int x) : val(x), next(nullptr) {}
8 * ListNode(int x, ListNode *next) : val(x), next(next) {}
9 * };
10 */
11class Solution {
12public:
13 ListNode* plusOne(ListNode* head) {
14 // Create a dummy node pointing to head to handle overflow case (e.g., 999 -> 1000)
15 ListNode* dummyHead = new ListNode(0, head);
16
17 // Find the rightmost node that is not 9
18 // This node will be incremented, and all nodes after it will become 0
19 ListNode* lastNonNineNode = dummyHead;
20
21 // Traverse the linked list to find the rightmost non-9 digit
22 for (ListNode* current = head; current != nullptr; current = current->next) {
23 if (current->val != 9) {
24 lastNonNineNode = current;
25 }
26 }
27
28 // Increment the rightmost non-9 digit
29 lastNonNineNode->val++;
30
31 // Set all digits after the incremented position to 0
32 // (These were all 9s that need to be carried over)
33 for (ListNode* current = lastNonNineNode->next; current != nullptr; current = current->next) {
34 current->val = 0;
35 }
36
37 // If dummy node was incremented (val != 0), we had an overflow
38 // Return dummy node; otherwise, return the original head
39 return (dummyHead->val != 0) ? dummyHead : dummyHead->next;
40 }
41};
42
1/**
2 * Definition for singly-linked list.
3 * class ListNode {
4 * val: number
5 * next: ListNode | null
6 * constructor(val?: number, next?: ListNode | null) {
7 * this.val = (val===undefined ? 0 : val)
8 * this.next = (next===undefined ? null : next)
9 * }
10 * }
11 */
12
13/**
14 * Adds one to a number represented as a linked list
15 * @param head - The head of the linked list representing a non-negative integer
16 * @returns The head of the linked list after adding one
17 */
18function plusOne(head: ListNode | null): ListNode | null {
19 // Create a dummy node pointing to head to handle the case where we need to add a new digit
20 const dummyNode: ListNode = new ListNode(0, head);
21
22 // Find the rightmost node that is not 9
23 // This will be the node we increment
24 let nodeToIncrement: ListNode = dummyNode;
25 let currentNode: ListNode | null = head;
26
27 // Traverse the list to find the last non-9 digit
28 while (currentNode) {
29 if (currentNode.val !== 9) {
30 nodeToIncrement = currentNode;
31 }
32 currentNode = currentNode.next;
33 }
34
35 // Increment the target node
36 nodeToIncrement.val++;
37
38 // Set all nodes after the incremented node to 0 (handle carry propagation)
39 let nodeToReset: ListNode | null = nodeToIncrement.next;
40 while (nodeToReset) {
41 nodeToReset.val = 0;
42 nodeToReset = nodeToReset.next;
43 }
44
45 // If dummy node was incremented, we need to include it in the result
46 // Otherwise, return the original head
47 return dummyNode.val > 0 ? dummyNode : dummyNode.next;
48}
49
Time and Space Complexity
Time Complexity: O(n)
, where n
is the length of the linked list.
The algorithm traverses the linked list twice:
- First traversal: The while loop iterates through all nodes once to find the rightmost non-9 digit, taking
O(n)
time. - Second traversal: In the worst case (when all digits after the target node are 9s), we traverse from the target node to the end of the list to set them to 0, which is at most
O(n)
time.
Since both traversals are sequential and not nested, the overall time complexity is O(n) + O(n) = O(n)
.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space:
dummy
: A single additional node created at the beginningtarget
: A pointer variable that references existing nodeshead
: A pointer variable used for traversal
No additional data structures that grow with input size are used. The algorithm modifies the linked list in-place, requiring only constant extra space regardless of the input size.
Common Pitfalls
Pitfall 1: Forgetting to Handle the All-9s Case
The Problem: A common mistake is trying to handle the carry operation without considering that all digits might be 9. Without proper handling, you might try to access a null pointer or fail to add the new most significant digit.
Why It Happens:
# Incorrect approach - doesn't handle all 9s properly
def plusOne_wrong(head):
# Find rightmost non-9
target = None
current = head
while current:
if current.val != 9:
target = current
current = current.next
# BUG: If all digits are 9, target is None!
target.val += 1 # This will crash with AttributeError
# ...
The Solution: Always use a dummy node that acts as a sentinel. This ensures you always have a valid node to increment:
dummy = ListNode(0, head) rightmost_not_nine = dummy # Guaranteed to have a valid node
Pitfall 2: Using Recursion or Stack (Space Inefficiency)
The Problem: Many developers instinctively reach for recursion or a stack to handle the carry from right to left, which uses O(n) extra space.
Why It Happens:
# Space-inefficient recursive approach
def plusOne_recursive(head):
def helper(node):
if not node:
return 1
carry = helper(node.next)
total = node.val + carry
node.val = total % 10
return total // 10
carry = helper(head)
if carry:
new_head = ListNode(1)
new_head.next = head
return new_head
return head
The Solution: The single-pass approach with the dummy node achieves the same result in O(1) space by identifying the rightmost non-9 digit first, then propagating changes forward.
Pitfall 3: Multiple Traversals
The Problem: Some solutions traverse the list multiple times - once to find the length, once to find where to add, and once to handle carries.
Why It Happens:
# Inefficient multi-pass approach
def plusOne_multipass(head):
# First pass: count length
length = 0
current = head
while current:
length += 1
current = current.next
# Second pass: find position to increment
# ... more traversals ...
The Solution: The optimal approach combines all operations into a single traversal, tracking the rightmost non-9 digit as we go, making the algorithm more efficient with just one pass through the list.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
Recommended Readings
Linked List Cycle Given a linked list with potentially a loop determine whether the linked list from the first node contains a cycle in it For bonus points do this with constant space Parameters nodes The first node of a linked list with potentially a loop Result Whether there is a loop contained
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!