Opening the reading…
Opening the reading…
LINKED LIST › LINKED LIST (PART 1)
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →Adding one affects the least significant digit first. If that digit is below 9, you increase it and stop. If it is 9, it becomes 0 and the carry continues to the digit before it. This is exactly the same carry rule used for an array of digits, except a singly linked list makes the last node difficult to reach from the front.
Reverse the links temporarily so the least significant digit becomes the first node. The carry can then move through the list in the natural forward direction. After the addition, reverse the links again to restore most-significant-digit-first order. If every original digit was 9, the carry survives the final node, so a new leading node containing 1 is required.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | The first reversal, the carry walk, and the second reversal each advance through the chain at most once. Their constant number of passes totals O(n), and no node causes nested traversal. |
| Space | O(1) extra | Only a constant number of node pointers and integers are used; the returned list is required output and is excluded. The bound stays O(1) even for the worst input shape, including a 100000-node chain. |
#include <cstddef>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int value) : val(value), next(nullptr) {}
};
class Solution {
ListNode* reverseList(ListNode* head) {
ListNode* previous = nullptr;
while (head != nullptr) {
ListNode* nextNode = head->next;
head->next = previous;
previous = head;
head = nextNode;
}
return previous;
}
public:
ListNode* addOne(ListNode* head) {
head = reverseList(head);
ListNode* current = head;
int carry = 1;
while (current != nullptr && carry != 0) {
int value = current->val + carry;
current->val = value % 10;
carry = value / 10;
if (carry != 0 && current->next == nullptr) {
current->next = new ListNode(0);
}
current = current->next;
}
head = reverseList(head);
if (carry != 0) {
ListNode* first = new ListNode(carry);
first->next = head;
head = first;
}
return head;
}
};The append-zero line is what lets the same loop handle both ordinary carry propagation and an all-9 suffix. For example, after reversing 99, the last existing node becomes 0 with carry 1; appending a zero gives the carry a place to write 1. The later prepend handles the carry that remains only after every existing digit has become 0.
You can avoid reversing the list by remembering the last node whose digit is not 9. Scan from the front, update that node by one, and turn every node after it into 0. Those later nodes are exactly the suffix that would have received the carry. If no such node exists, every digit is 9 and a new leading 1 is needed.
#include <cstddef>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int value) : val(value), next(nullptr) {}
};
class Solution {
public:
ListNode* addOne(ListNode* head) {
ListNode* lastNotNine = nullptr;
ListNode* current = head;
while (current != nullptr) {
if (current->val != 9) {
lastNotNine = current;
}
current = current->next;
}
if (lastNotNine == nullptr) {
ListNode* first = new ListNode(1);
first->next = head;
head = first;
lastNotNine = head;
} else {
++lastNotNine->val;
}
current = lastNotNine->next;
while (current != nullptr) {
current->val = 0;
current = current->next;
}
return head;
}
};This is a different arrangement rather than an asymptotic improvement: it is still O(n) time and O(1) extra space. It avoids two reversals and never changes links, which can make the code easier to reason about when link order must remain stable. The reverse-based version mirrors the carry process more directly and is a useful pattern whenever a singly linked list requires backward-style processing.