Start learning free

LESSON 281 OF 348 · LINKED LISTS

Add Two Numbers in Kotlin: Linked Lists with a Carry

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

    KOTLIN · LINKED LISTS

    Add Two Numbers in Kotlin, explained

    Problem overview

    Two non-negative integers arrive as linked lists, list1 and list2. Each node holds one digit, and the digits are stored in reverse order: the first node is the ones digit, the second is the tens digit, and so on. The function addTwoNumbers must return their sum as a list in the same format.

    For [2, 4, 3] and [5, 6, 4] the numbers are 342 and 465. Their sum is 807, so the result is [7, 0, 8]. The second example, [9,9,9,9,9,9,9] plus [9,9,9,9], is 9999999 + 9999 = 10009998, so the result is [8, 9, 9, 9, 0, 0, 0, 1]. The result is one node longer than either input because of a final carry.

    Approach: column addition, digit by digit

    The reversed order is a gift. Adding by hand starts at the ones column and moves left, and the lists already begin with the ones digit. So you can add the way you did on paper: take the two digits in a column, add the carry from the previous column, write down the last digit of the total and carry the rest.

    The digits never need to be turned into one big number. That matters because the lists can be long, and a number with hundreds of digits doesn't fit in an Int or a Long. Working one column at a time uses only small values.

    When one list is shorter, its missing digits count as 0. When both lists are finished but a carry remains, as in the second example, one more digit is added to the result.

    Step by step

    1. Create two cursors, node1 and node2, as vars starting at the heads. They move as the digits are consumed, and the parameters themselves stay untouched.
    2. Create a dummy head and a tail cursor. The dummy node is scaffolding: because the result list always starts with a node you make, appending the first digit works the same as appending any other, with no special case. head never changes, so it is a val. tail moves, so it is a var.
    3. Start carry at 0. It holds what overflowed from the previous column. A column's total is at most 9 + 9 + 1 = 19, so the carry is only ever 0 or 1.
    4. Loop while there is anything left to add: a digit in either list, or a carry. The third condition is what produces the extra node at the end of the second example.
    5. Seed digitSum with carry. This counts the overflow from the previous column first.
    6. Add the digit of each list that still has one, and move that cursor forward. These are two separate if statements, not an if/else, because both lists can contribute to the same column.
    7. Compute the new carry with an if expression: 1 when digitSum is above 9, otherwise 0.
    8. Reduce digitSum to one digit with %= 10.
    9. Append a new ListNode holding that digit to tail.next, then move tail onto it.
    10. Return head.next. The dummy node holds a placeholder 0 and isn't part of the answer.

    The solution in Kotlin

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

    The Kotlin details worth knowing:

    • Backticks around val. val is a keyword, but the node's field has that name, so it is written node1.`val`. Backticks let a keyword be used as an ordinary name.
    • Smart casts. After if (node1 != null), Kotlin treats the local var node1 as a non-null ListNode inside the block, so node1.`val` needs no ?. or !!. This works because node1 is a local variable that nothing else can change in between.
    • tail.next!!. The property next is declared ListNode?, while tail is a non-null ListNode. Kotlin doesn't remember that the line above just assigned a node, so !! asserts that it isn't null. It would throw if it were, but here it never is.
    • if as an expression. Kotlin has no ternary operator. if (digitSum > 9) 1 else 0 is an expression that yields a value, so it can sit on the right of =.
    • Semicolons. They are optional in Kotlin, but a semicolon lets two statements share a line, as in var node1 = list1; var node2 = list2.
    • ListNode() with no argument creates the dummy node with the default digit 0.

    Complexity

    Time: O(max(m, n)), where m and n are the lengths of the lists. The loop runs once per column, which is the length of the longer list, plus at most one extra time for a final carry. Each iteration does a constant amount of work.

    Space: O(max(m, n)) for the result, which has one node per output digit. Apart from the result, only a few variables are used.

    Edge cases and common mistakes

    • Lists of different lengths. [1, 8] plus [0] gives [1, 8]. Once node2 is null, the second if is skipped, which is the same as adding 0.
    • A final carry. [5] plus [5] gives [0, 1]. Without carry > 0 in the loop condition, the leading 1 would be lost.
    • Zero. [0] plus [0] gives [0], a single node. The loop runs once because both lists have a digit.
    • Using else for the second list. This skips digits whenever both lists have one.
    • Returning head. That includes the dummy 0 at the front, which makes the sum ten times too big.
    • Converting to numbers. A list of 30 nines overflows both Int and Long. Column addition has no such limit.
    • Writing the digits in the wrong order. The result must also have the ones digit first, so each new digit goes at the end of the list.

    Testing

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