Start learning free

LESSON 280 OF 347 · LINKED LISTS

Add Two Numbers in C#: Digit-by-Digit Addition on Linked Lists

Practice O(n) Read the full explanation

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example 1:

Input: list1 = [2, 4, 3], list2 = [5, 6, 4]
Output: [7, 0, 8]
Explanation: 342 + 465 = 807


Example 2:

Input: list1 = [9,9,9,9,9,9,9], list2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
Explanation: 9999999 + 9999 = 10009998


STEP 1 OF 12
    Ctrl + Enter to check

    C# · LINKED LISTS

    Add Two Numbers in C#, explained

    Problem overview

    Two non-negative integers arrive as linked lists, with one digit per node and the least significant digit first. AddTwoNumbers(list1, list2) must return their sum as a new linked list in the same format. Neither number has leading zeros, except the number 0 itself, and neither list is empty.

    In the first example, [2, 4, 3] is the number 342 and [5, 6, 4] is 465. Their sum is 807, which is stored backwards as [7, 0, 8]. In the second example, 9999999 + 9999 = 10009998 produces [8, 9, 9, 9, 0, 0, 0, 1]: the result is one node longer than either input, because a carry survives past the last column.

    Approach: add column by column, like on paper

    The reversed order is a gift. Addition on paper starts at the rightmost digit and moves left, and these lists start at exactly the digit you need first. So the plan is the schoolbook method:

    1. Add the two digits in the current column, plus any carry from the previous column.
    2. Write the last digit of that sum into a new result node.
    3. Carry 1 into the next column if the sum was 10 or more.

    Converting each list to an integer and adding the integers is tempting, but it breaks on long lists, because the numbers can have more digits than any integer type holds. Working digit by digit never builds a large number, so the length doesn't matter. The algorithm visits each node once and runs in linear time.

    The lists can have different lengths. Once one list runs out, its missing digits count as 0 and the other list keeps contributing. When both lists are exhausted, a leftover carry still needs one more node, which is why 9999999 + 9999 ends with an extra 1.

    Step by step

    1. Create two cursors. node1 and node2 walk the lists, so list1 and list2 keep pointing at the heads. C# allows several variables of one type in a single declaration.
    2. Create a dummy head. The result list needs a first node, but you don't know its value until the first column is added. A throwaway node at the front, with tail starting on it, lets every real digit be appended the same way, with no special case for the first one.
    3. Start the carry at 0. The first column has nothing to carry in.
    4. Loop while there is work. The condition has three parts joined by ||: the first list has a digit, the second list has a digit, or a carry is waiting. The last part is what produces the extra node at the end.
    5. Seed the column sum with the carry. A fresh digitSum per iteration starts as the carry from the previous column.
    6. Add each list's digit if it exists. Use two separate if statements, not if/else, because both lists usually have a digit in the same column. Each one also moves its cursor forward.
    7. Work out the new carry. A column sum above 9 carries 1 into the next column. The biggest possible sum is 9 + 9 + 1 = 19, so the carry is never more than 1.
    8. Keep only the last digit. digitSum %= 10 turns 15 into 5 and leaves 7 as 7.
    9. Append a node and move on. Hang the new node on tail.next, then move tail onto it so the next digit goes after it.
    10. Return head.next. The dummy node isn't part of the answer, so the result starts just after it.

    The solution in C#

    class Solution {
        public ListNode AddTwoNumbers(ListNode list1, ListNode list2) {
            ListNode node1 = list1, node2 = list2;
            ListNode head = new ListNode(), tail = head;
            int carry = 0;
            while (node1 != null || node2 != null || carry > 0) {
                int digitSum = carry;
                if (node1 != null) {
                    digitSum += node1.val;
                    node1 = node1.next;
                }
                if (node2 != null) {
                    digitSum += node2.val;
                    node2 = node2.next;
                }
                carry = (digitSum > 9) ? 1 : 0;
                digitSum %= 10;
                tail.next = new ListNode(digitSum);
                tail = tail.next;
            }
            return head.next;
        }
    }
    

    A few C# details are worth a closer look:

    • Booleans are not integers. In some languages carry = digitSum > 9; stores 1 or 0. In C# that line doesn't compile, because a bool can't be converted to an int. The conditional operator condition ? 1 : 0 makes the conversion explicit. Integer division gives another route: carry = digitSum / 10 is 1 for sums from 10 to 19 and 0 below that.
    • Explicit null checks. A condition must be a bool, so while (node1) is not allowed. Write node1 != null.
    • %= is shorthand. digitSum %= 10 means digitSum = digitSum % 10.
    • The dummy node comes from new ListNode(). Its val is 0 by default and it is never returned. Because ListNode is a class, tail = head copies a reference, not the node. Both variables point at the same object, and tail.next = … modifies the list that head still points to.
    • The cursors are local copies. Moving node1 doesn't change list1, and the input lists are never modified.

    Complexity

    Time: O(max(m, n)), where m and n are the lengths of the two lists. Each iteration consumes one digit from each list that still has one, and there is at most one extra iteration for the final carry.

    Space: O(max(m, n)) for the result list, which is the output itself. Apart from that, the code uses a few variables, so the extra space is O(1).

    Edge cases and common mistakes

    • A carry after the last digit. [5] plus [5] must give [0, 1]. A loop that only checks the two lists stops after the first column and loses the 1.
    • Different lengths. [1, 8] plus [0] works because the missing digit counts as 0. Reading node2.val without a null check would throw a NullReferenceException.
    • Zero plus zero. [0] plus [0] gives [0], one node. The loop runs once, and nothing is carried, so it stops.
    • A carry chain. Adding [9, 9, 9] and [1] carries through every column and ends with [0, 0, 0, 1].
    • Using if/else for the two lists. That adds only one list's digit per column.
    • Forgetting to advance tail. Each new digit would overwrite the previous one and the result would hold at most one real node.
    • Returning head. That includes the dummy node, which puts an extra 0 at the front.

    Testing

    • [2, 4, 3] and [5, 6, 4] give [7, 0, 8].
    • [9, 9, 9, 9, 9, 9, 9] and [9, 9, 9, 9] give [8, 9, 9, 9, 0, 0, 0, 1].
    • [0] and [0] give [0].
    • [5] and [5] give [0, 1].
    Keep going with C#About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free