A clear explanation of adding one to a number stored as a linked list using the rightmost non-nine digit.
Problem Restatement
We are given the head of a non-empty singly linked list.
The linked list represents a non-negative integer.
Each node stores one digit from 0 to 9.
The digits are stored in normal order, so the most significant digit is at the head.
For example:
1 -> 2 -> 3represents the number:
123We need to add 1 to this number and return the head of the resulting linked list.
The number has no leading zero unless the number itself is 0. The official examples include [1,2,3] -> [1,2,4] and [0] -> [1].
Input and Output
| Item | Meaning |
|---|---|
| Input | Head of a singly linked list |
| Output | Head of the linked list after adding one |
| Digit order | Most significant digit first |
| Node values | 0 through 9 |
| List length | 1 to 100 |
Example function shape:
def plusOne(head: Optional[ListNode]) -> Optional[ListNode]:
...Examples
Example 1:
1 -> 2 -> 3This represents 123.
After adding one:
123 + 1 = 124The output is:
1 -> 2 -> 4Example 2:
1 -> 2 -> 9This represents 129.
After adding one:
129 + 1 = 130The output is:
1 -> 3 -> 0Example 3:
9 -> 9 -> 9This represents 999.
After adding one:
999 + 1 = 1000The output is:
1 -> 0 -> 0 -> 0First Thought: Reverse the List
One direct way is:
- Reverse the linked list.
- Add one from the least significant digit.
- Propagate carry.
- Reverse the list back.
This works, but it modifies the list structure twice.
We can solve it in one forward traversal without reversing.
Key Insight
Only trailing 9s cause carry propagation.
For example:
1 -> 2 -> 9 -> 9Adding one gives:
1 -> 3 -> 0 -> 0The last non-9 digit before the trailing 9s is 2.
We increment it to 3.
Then every digit after it becomes 0.
So the main task is:
find the rightmost node whose value is not 9If every digit is 9, we need a new leading 1.
A dummy node solves this cleanly.
For:
9 -> 9 -> 9create:
0 -> 9 -> 9 -> 9The rightmost non-9 node is the dummy 0.
Increment it:
1 -> 9 -> 9 -> 9Set all following nodes to 0:
1 -> 0 -> 0 -> 0Return the dummy node because its value became 1.
Algorithm
- Create a dummy node with value
0. - Link it before
head. - Set
target = dummy. - Traverse the list.
- Whenever a node value is not
9, updatetargetto that node. - After traversal, increment
target.val. - Set every node after
targetto0. - If
dummy.val == 1, returndummy. - Otherwise, return
dummy.next.
Correctness
The only digits affected by adding one are the trailing run of 9s and the digit immediately before that run.
If the number does not end in 9, the last digit is the rightmost non-9 digit. Incrementing it is enough.
If the number ends in one or more 9s, each trailing 9 becomes 0, and the carry moves left until it reaches the rightmost non-9 digit. That digit increases by one.
The algorithm finds exactly this rightmost non-9 node as target.
After incrementing target, all nodes after it must be trailing 9s, so setting them to 0 correctly applies the carry.
If all original digits are 9, the dummy node remains the rightmost non-9 node. Incrementing it creates the new leading 1, and all original nodes become 0.
Therefore, the returned linked list represents the original number plus one.
Complexity
Let n be the number of nodes.
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | We traverse the list once, then zero out a suffix |
| Space | O(1) | Only a few pointers are used |
Implementation
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def plusOne(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
target = dummy
current = head
while current:
if current.val != 9:
target = current
current = current.next
target.val += 1
current = target.next
while current:
current.val = 0
current = current.next
if dummy.val == 1:
return dummy
return dummy.nextCode Explanation
The dummy node handles the all-9s case:
dummy = ListNode(0)
dummy.next = headWe start target at the dummy:
target = dummyThen we scan the original list:
while current:
if current.val != 9:
target = current
current = current.nextAfter this loop, target is the rightmost node that can absorb the carry.
We increment it:
target.val += 1Every node after target was a trailing 9, so it becomes 0:
current = target.next
while current:
current.val = 0
current = current.nextIf the dummy changed from 0 to 1, it is now part of the result:
if dummy.val == 1:
return dummyOtherwise, skip it:
return dummy.nextTesting
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def build(values):
dummy = ListNode()
current = dummy
for value in values:
current.next = ListNode(value)
current = current.next
return dummy.next
def to_list(head):
values = []
while head:
values.append(head.val)
head = head.next
return values
def run_tests():
s = Solution()
assert to_list(s.plusOne(build([1, 2, 3]))) == [1, 2, 4]
assert to_list(s.plusOne(build([1, 2, 9]))) == [1, 3, 0]
assert to_list(s.plusOne(build([9, 9, 9]))) == [1, 0, 0, 0]
assert to_list(s.plusOne(build([0]))) == [1]
assert to_list(s.plusOne(build([8, 9, 9]))) == [9, 0, 0]
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
[1,2,3] | No carry chain |
[1,2,9] | Carry through one trailing 9 |
[9,9,9] | Creates a new leading node |
[0] | Smallest number |
[8,9,9] | Carry through multiple trailing 9s |