2
\$\begingroup\$

(...as I still learning Kotlin) I found this "problem":

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

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)

Output: 7 -> 0 -> 8

This is my solution so far:

fun add(a: IntArray, b: IntArray): Iterable<Int> {
  val result: MutableList<Int> = mutableListOf()
  var remainder = 0
  for (i in 0..Math.max(a.size, b.size) - 1) {
    val sum = a.elementAtOrElse(i, { 0 }) + b.elementAtOrElse(i, { 0 }) + remainder
    remainder = if (sum >= 10) 1 else 0
    result.add(if (remainder >= 1) sum - 10 else sum)
  }
  if (remainder > 0) result.add(remainder)
  return result
}

...test cases:

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test

class AddTwoNumbersTest {
  @Test
  fun test_Add() {
    assertThat(add(intArrayOf(9, 6, 9, 5, 9), intArrayOf(1, 5, 1, 6, 1))).isEqualTo(listOf(0, 2, 1, 2, 1, 1))
    assertThat(add(intArrayOf(4, 1, 8, 7, 2), intArrayOf(9, 4, 1, 0, 3))).isEqualTo(listOf(3, 6, 9, 7, 5))
    assertThat(add(intArrayOf(2, 2, 3, 3), intArrayOf(4, 5, 6, 7))).isEqualTo(listOf(6, 7, 9, 0, 1))
    assertThat(add(intArrayOf(4, 1, 0, 8), intArrayOf(2, 2, 7, 6))).isEqualTo(listOf(6, 3, 7, 4, 1))
    assertThat(add(intArrayOf(2, 7, 1, 0), intArrayOf(0, 0, 8, 1))).isEqualTo(listOf(2, 7, 9, 1))
    assertThat(add(intArrayOf(9, 9, 9), intArrayOf(9, 9, 9))).isEqualTo(listOf(8, 9, 9, 1))
    assertThat(add(intArrayOf(9, 3, 7), intArrayOf(8, 7, 8))).isEqualTo(listOf(7, 1, 6, 1))
    assertThat(add(intArrayOf(6, 6, 6), intArrayOf(7, 8, 9))).isEqualTo(listOf(3, 5, 6, 1))
    assertThat(add(intArrayOf(0, 0, 0), intArrayOf(0, 0, 0))).isEqualTo(listOf(0, 0, 0))
    assertThat(add(intArrayOf(2, 4, 3), intArrayOf(5, 6, 4))).isEqualTo(listOf(7, 0, 8))
    assertThat(add(intArrayOf(0, 1), intArrayOf(0, 1, 2))).isEqualTo(listOf(0, 2, 2))
    assertThat(add(intArrayOf(4, 6), intArrayOf(6, 4))).isEqualTo(listOf(0, 1, 1))
    assertThat(add(intArrayOf(1), intArrayOf(9, 9))).isEqualTo(listOf(0, 0, 1))
    assertThat(add(intArrayOf(), intArrayOf(0, 1))).isEqualTo(listOf(0, 1))
    assertThat(add(intArrayOf(), intArrayOf())).isEmpty()
  }
}

It works so far...so I'm wondering if you can improve this one, or have a better approach. Notice I use everything the language offer.

\$\endgroup\$
  • \$\begingroup\$ FYI: The "problem" calls for linked lists but you've used arrays. You might consider converting the Java code to Kotlin using IntelliJ IDEA or try.kotlinlang.org. \$\endgroup\$ – mfulton26 Jan 1 '17 at 4:19
  • \$\begingroup\$ But leetcode has no support to judge your solution with Kotlin. \$\endgroup\$ – Richard May 29 '17 at 23:20
2
\$\begingroup\$
  1. Using add as a function name seems very ambiguous. The method name used in the Java Solution class from LeetCode seems more appropriate: addTwoNumbers (thereby specifying that the arguments, although not numbers themselves, represent numbers).
  2. You can remove the explicit type specification for var result if you add explicit type arguments to mutableListOf(). I personally find this more readable and less verbose:

    var result = mutableListOf<Int>()
    
  3. You can use start until endExclusive instead of start..endInclusive - 1:

    for (i in 0 until Math.max(a.size, b.size))
    
  4. You can use the slightly shorter getOrElse instead of elementAtOrElse. You can also move trailing lambda arguments out of parentheses:

    val sum = a.getOrElse(i) { 0 } + b.getOrElse(i) { 0 } + remainder
    
  5. You can use an overloaded operator for adding elements to a mutable list:

    result += if (remainder >= 1) sum - 10 else sum
    
  6. I wouldn't use remainder >= 1 or remainder > 0 because it makes it appear that remainder can be greater than 1 which is not true. I recommend using remainder == 1.

Altogether:

fun addTwoNumbers(a: IntArray, b: IntArray): Iterable<Int> {
    val result = mutableListOf<Int>()
    var remainder = 0
    for (i in 0 until Math.max(a.size, b.size)) {
        val sum = a.getOrElse(i) { 0 } + b.getOrElse(i) { 0 } + remainder
        remainder = if (sum >= 10) 1 else 0
        result += if (remainder == 1) sum - 10 else sum
    }
    if (remainder == 1) result.add(1)
    return result
}

However, the "problem" specified in LeetCode does not use arrays which are very different from linked lists. If you convert the Java code it provides you would get the following:

/**
 * Definition for singly-linked list.
 * class ListNode internal constructor(internal var `val`: Int) {
 *     internal var next: ListNode? = null
 * }
 */
class Solution {
    fun addTwoNumbers(l1: ListNode, l2: ListNode): ListNode {

    }
}

Solving such a problem should result in a very different solution than what you've arrived at.

\$\endgroup\$
  • \$\begingroup\$ Yeah, I'm aware the solution would be completely different if I have to use their ListNode type; but I'm just "playing" with Kotlin right now, so I'm not pursuing the problem's solution as it's written, but something close that let me practice. BTW, your observations/recommendations are pretty cool...all of them! \$\endgroup\$ – x80486 Jan 5 '17 at 16:33
  • \$\begingroup\$ Yeah, I would avoid using their ListNode too. :-) I'm glad I could help. An exercise in Kotlin that would be more similar and perhaps more entertaining would be to use Sequence<Int> instead of IntArray. IntArray allows random access to its elements and the size/length is known up front while Sequence<Int> does not and it would be inefficient to convert the Sequence<Int> to IntArray, List<Int>, etc. \$\endgroup\$ – mfulton26 Jan 5 '17 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.